mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
Add license management
This commit is contained in:
parent
74dcf0fe7c
commit
d55805ba4e
@ -5,6 +5,7 @@ import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletException;
|
||||
@ -17,6 +18,7 @@ import org.apache.shiro.SecurityUtils;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
|
||||
import com.gitplex.server.manager.ConfigManager;
|
||||
import com.gitplex.server.manager.ProjectManager;
|
||||
import com.gitplex.server.manager.UserManager;
|
||||
import com.gitplex.server.model.Project;
|
||||
@ -26,9 +28,11 @@ import com.gitplex.server.model.User;
|
||||
import com.gitplex.server.model.support.BranchProtection;
|
||||
import com.gitplex.server.model.support.TagProtection;
|
||||
import com.gitplex.server.persistence.annotation.Sessional;
|
||||
import com.gitplex.server.persistence.dao.EntityCriteria;
|
||||
import com.gitplex.server.security.ProjectPrivilege;
|
||||
import com.gitplex.server.security.permission.ProjectPermission;
|
||||
import com.gitplex.utils.StringUtils;
|
||||
import com.gitplex.utils.license.LicenseDetail;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
@ -41,18 +45,24 @@ public class GitPreReceiveCallback extends HttpServlet {
|
||||
|
||||
private final UserManager userManager;
|
||||
|
||||
private final ConfigManager configManager;
|
||||
|
||||
@Inject
|
||||
public GitPreReceiveCallback(ProjectManager projectManager, UserManager userManager) {
|
||||
public GitPreReceiveCallback(ProjectManager projectManager, UserManager userManager, ConfigManager configManager) {
|
||||
this.projectManager = projectManager;
|
||||
this.userManager = userManager;
|
||||
this.configManager = configManager;
|
||||
}
|
||||
|
||||
private void error(Output output, String refName, String... messages) {
|
||||
private void error(Output output, @Nullable String refName, String... messages) {
|
||||
output.markError();
|
||||
output.writeLine();
|
||||
output.writeLine("*******************************************************");
|
||||
output.writeLine("*");
|
||||
output.writeLine("* ERROR PUSHING REF: " + refName);
|
||||
if (refName != null)
|
||||
output.writeLine("* ERROR PUSHING REF: " + refName);
|
||||
else
|
||||
output.writeLine("* ERROR PUSHING");
|
||||
output.writeLine("-------------------------------------------------------");
|
||||
for (String message: messages)
|
||||
output.writeLine("* " + message);
|
||||
@ -64,6 +74,18 @@ public class GitPreReceiveCallback extends HttpServlet {
|
||||
@Sessional
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
int userCount = userManager.count(EntityCriteria.of(User.class));
|
||||
int licenseLimit = LicenseDetail.FREE_LICENSE_USERS;
|
||||
LicenseDetail license = configManager.getLicense();
|
||||
if (license != null && license.getRemainingDays() >= 0) {
|
||||
licenseLimit += license.getLicensedUsers();
|
||||
}
|
||||
if (userCount > licenseLimit) {
|
||||
String message = String.format("Push is disabled as number of users in system exceeds license limit");
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, message);
|
||||
return;
|
||||
}
|
||||
|
||||
String clientIp = request.getHeader("X-Forwarded-For");
|
||||
if (clientIp == null) clientIp = request.getRemoteAddr();
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ import com.gitplex.server.model.support.setting.SecuritySetting;
|
||||
import com.gitplex.server.model.support.setting.SystemSetting;
|
||||
import com.gitplex.server.persistence.dao.EntityManager;
|
||||
import com.gitplex.server.security.authenticator.Authenticator;
|
||||
import com.gitplex.utils.license.LicenseDetail;
|
||||
|
||||
public interface ConfigManager extends EntityManager<Config> {
|
||||
|
||||
@ -93,4 +94,9 @@ public interface ConfigManager extends EntityManager<Config> {
|
||||
|
||||
void saveAuthenticator(@Nullable Authenticator authenticator);
|
||||
|
||||
@Nullable
|
||||
LicenseDetail getLicense();
|
||||
|
||||
void saveLicense(@Nullable LicenseDetail license);
|
||||
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@ import com.gitplex.server.persistence.dao.AbstractEntityManager;
|
||||
import com.gitplex.server.persistence.dao.Dao;
|
||||
import com.gitplex.server.persistence.dao.EntityCriteria;
|
||||
import com.gitplex.server.security.authenticator.Authenticator;
|
||||
import com.gitplex.utils.license.LicenseDetail;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
@Singleton
|
||||
@ -37,6 +38,8 @@ public class DefaultConfigManager extends AbstractEntityManager<Config> implemen
|
||||
|
||||
private volatile Long authenticatorConfigId;
|
||||
|
||||
private volatile Long licenseConfigId;
|
||||
|
||||
@Inject
|
||||
public DefaultConfigManager(Dao dao, DataManager dataManager) {
|
||||
super(dao);
|
||||
@ -190,5 +193,31 @@ public class DefaultConfigManager extends AbstractEntityManager<Config> implemen
|
||||
config.setSetting(null);
|
||||
dao.persist(config);
|
||||
}
|
||||
|
||||
@Sessional
|
||||
@Override
|
||||
public LicenseDetail getLicense() {
|
||||
Config config;
|
||||
if (licenseConfigId == null) {
|
||||
config = getConfig(Key.LICENSE);
|
||||
Preconditions.checkNotNull(config);
|
||||
licenseConfigId = config.getId();
|
||||
} else {
|
||||
config = load(licenseConfigId);
|
||||
}
|
||||
return (LicenseDetail) config.getSetting();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveLicense(LicenseDetail license) {
|
||||
Config config = getConfig(Key.LICENSE);
|
||||
if (config == null) {
|
||||
config = new Config();
|
||||
config.setKey(Key.LICENSE);
|
||||
}
|
||||
config.setSetting(license);
|
||||
dao.persist(config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -186,6 +186,11 @@ public class DefaultDataManager implements DataManager, Serializable {
|
||||
});
|
||||
}
|
||||
|
||||
Config licenseKeyConfig = configManager.getConfig(Key.LICENSE);
|
||||
if (licenseKeyConfig == null) {
|
||||
configManager.saveLicense(null);
|
||||
}
|
||||
|
||||
return manualConfigs;
|
||||
}
|
||||
|
||||
|
||||
@ -387,4 +387,22 @@ public class DatabaseMigrator {
|
||||
}
|
||||
}
|
||||
|
||||
private void migrate11(File dataDir, Stack<Integer> versions) {
|
||||
for (File file: dataDir.listFiles()) {
|
||||
if (file.getName().startsWith("Configs.xml")) {
|
||||
VersionedDocument dom = VersionedDocument.fromFile(file);
|
||||
long maxId = 0;
|
||||
for (Element element: dom.getRootElement().elements()) {
|
||||
Long id = Long.parseLong(element.elementTextTrim("id"));
|
||||
if (maxId < id)
|
||||
maxId = id;
|
||||
}
|
||||
Element licenseConfigElement = dom.getRootElement().addElement("com.gitplex.server.model.Config");
|
||||
licenseConfigElement.addElement("id").setText(String.valueOf(maxId+1));
|
||||
licenseConfigElement.addElement("key").setText("LICENSE");
|
||||
dom.writeToFile(file, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ public class Config extends AbstractEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public enum Key {SYSTEM, MAIL, BACKUP, SECURITY, AUTHENTICATOR};
|
||||
public enum Key {SYSTEM, MAIL, BACKUP, SECURITY, AUTHENTICATOR, LICENSE};
|
||||
|
||||
/*
|
||||
* Optimistic lock is necessary to ensure database integrity when update
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
<dependency>
|
||||
<groupId>org.webjars</groupId>
|
||||
<artifactId>font-awesome</artifactId>
|
||||
<version>4.5.0</version>
|
||||
<version>4.7.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.webjars</groupId>
|
||||
|
||||
@ -11,6 +11,7 @@ import org.apache.wicket.request.mapper.CompoundRequestMapper;
|
||||
|
||||
import com.gitplex.server.web.page.admin.authenticator.AuthenticatorPage;
|
||||
import com.gitplex.server.web.page.admin.databasebackup.DatabaseBackupPage;
|
||||
import com.gitplex.server.web.page.admin.licensemanagement.LicenseManagementPage;
|
||||
import com.gitplex.server.web.page.admin.mailsetting.MailSettingPage;
|
||||
import com.gitplex.server.web.page.admin.securitysetting.SecuritySettingPage;
|
||||
import com.gitplex.server.web.page.admin.serverinformation.ServerInformationPage;
|
||||
@ -103,6 +104,7 @@ public class GitPlexUrlMapper extends CompoundRequestMapper {
|
||||
add(new GitPlexPageMapper("administration/settings/authenticator", AuthenticatorPage.class));
|
||||
add(new GitPlexPageMapper("administration/server-log", ServerLogPage.class));
|
||||
add(new GitPlexPageMapper("administration/server-information", ServerInformationPage.class));
|
||||
add(new GitPlexPageMapper("administration/license-management", LicenseManagementPage.class));
|
||||
}
|
||||
|
||||
private void addUserPages() {
|
||||
|
||||
@ -16,6 +16,7 @@ import com.gitplex.server.web.component.tabbable.PageTab;
|
||||
import com.gitplex.server.web.component.tabbable.Tabbable;
|
||||
import com.gitplex.server.web.page.admin.authenticator.AuthenticatorPage;
|
||||
import com.gitplex.server.web.page.admin.databasebackup.DatabaseBackupPage;
|
||||
import com.gitplex.server.web.page.admin.licensemanagement.LicenseManagementPage;
|
||||
import com.gitplex.server.web.page.admin.mailsetting.MailSettingPage;
|
||||
import com.gitplex.server.web.page.admin.securitysetting.SecuritySettingPage;
|
||||
import com.gitplex.server.web.page.admin.serverinformation.ServerInformationPage;
|
||||
@ -43,6 +44,7 @@ public abstract class AdministrationPage extends LayoutPage {
|
||||
tabs.add(new AdministrationTab("Database Backup", "fa fa-fw fa-database", DatabaseBackupPage.class));
|
||||
tabs.add(new AdministrationTab("Server Log", "fa fa-fw fa-file-text-o", ServerLogPage.class));
|
||||
tabs.add(new AdministrationTab("Server Information", "fa fa-fw fa-desktop", ServerInformationPage.class));
|
||||
tabs.add(new AdministrationTab("License Management", "fa fa-fw fa-vcard-o", LicenseManagementPage.class));
|
||||
|
||||
add(new Tabbable("tabs", tabs));
|
||||
}
|
||||
|
||||
@ -27,3 +27,15 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
.license-detail .properties td {
|
||||
padding: 0 16px 16px 0;
|
||||
}
|
||||
.license-detail .properties tr:last-child td {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.license-detail .properties td.name {
|
||||
width: 200px;
|
||||
}
|
||||
.license-management .actions a {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
<wicket:extend>
|
||||
<div class="license-management panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Current License</h4>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div wicket:id="licenseDetail"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a wicket:id="inputLicenseKey" class="btn btn-primary">Install New License</a>
|
||||
<a wicket:id="removeLicense" class="btn btn-danger">Remove Current License</a>
|
||||
</div>
|
||||
<wicket:fragment wicket:id="licenseDetailFrag">
|
||||
<div class="license-detail">
|
||||
<div wicket:id="expiredNotice" class="expired alert alert-danger"></div>
|
||||
<div wicket:id="aboutToExpireNotice" class="about-to-expire alert alert-warning"></div>
|
||||
<table class="properties">
|
||||
<tr>
|
||||
<td class="name">Users</td>
|
||||
<td wicket:id="users" class="value"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name">Issue Date</td>
|
||||
<td wicket:id="issueDate" class="value"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name">Expiration Date</td>
|
||||
<td wicket:id="expirationDate" class="value"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</wicket:fragment>
|
||||
<wicket:fragment wicket:id="licenseKeyInputFrag">
|
||||
<form wicket:id="form" class="credit-key-input">
|
||||
<div class="modal-header">
|
||||
<button wicket:id="close" type="button" class="close">×</button>
|
||||
<h4 class="modal-title">Input License Key</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div wicket:id="feedback"></div>
|
||||
<textarea wicket:id="licenseKey" rows="10" class="form-control autofocus"></textarea>
|
||||
<p class="help-block">License key can be generated from account at
|
||||
<a href="https://www.gitplex.com">gitplex.com</a>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button wicket:id="ok" class="btn btn-primary">Ok</button>
|
||||
<button wicket:id="cancel" class="btn btn-default">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</wicket:fragment>
|
||||
</wicket:extend>
|
||||
@ -0,0 +1,226 @@
|
||||
package com.gitplex.server.web.page.admin.licensemanagement;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
import org.apache.wicket.ajax.markup.html.AjaxLink;
|
||||
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.form.Form;
|
||||
import org.apache.wicket.markup.html.form.TextArea;
|
||||
import org.apache.wicket.markup.html.link.Link;
|
||||
import org.apache.wicket.markup.html.panel.Fragment;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.gitplex.server.GitPlex;
|
||||
import com.gitplex.server.manager.ConfigManager;
|
||||
import com.gitplex.server.manager.UserManager;
|
||||
import com.gitplex.server.model.User;
|
||||
import com.gitplex.server.persistence.dao.EntityCriteria;
|
||||
import com.gitplex.server.web.WebConstants;
|
||||
import com.gitplex.server.web.component.modal.ModalLink;
|
||||
import com.gitplex.server.web.component.modal.ModalPanel;
|
||||
import com.gitplex.server.web.page.admin.AdministrationPage;
|
||||
import com.gitplex.server.web.util.ConfirmOnClick;
|
||||
import com.gitplex.utils.license.LicenseDetail;
|
||||
|
||||
import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class LicenseManagementPage extends AdministrationPage {
|
||||
|
||||
private static final String LICENSE_DETAIL_ID = "licenseDetail";
|
||||
|
||||
private String licenseKey;
|
||||
|
||||
private final IModel<LicenseDetail> licenseModel = new LoadableDetachableModel<LicenseDetail>() {
|
||||
|
||||
@Override
|
||||
protected LicenseDetail load() {
|
||||
return GitPlex.getInstance(ConfigManager.class).getLicense();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final IModel<Integer> userCountModel = new LoadableDetachableModel<Integer>() {
|
||||
|
||||
@Override
|
||||
protected Integer load() {
|
||||
return GitPlex.getInstance(UserManager.class).count(EntityCriteria.of(User.class));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
LicenseDetail licenseDetail = getLicense();
|
||||
if (licenseDetail != null) {
|
||||
Fragment fragment = new Fragment(LICENSE_DETAIL_ID, "licenseDetailFrag", this);
|
||||
fragment.add(new Label("expiredNotice", new LoadableDetachableModel<String>() {
|
||||
|
||||
@Override
|
||||
protected String load() {
|
||||
return String.format("License was expired. The free %d-user license is now taking effect",
|
||||
LicenseDetail.FREE_LICENSE_USERS);
|
||||
}
|
||||
|
||||
}).setVisible(licenseDetail.getRemainingDays()<0).setEscapeModelStrings(false));
|
||||
|
||||
fragment.add(new Label("aboutToExpireNotice", new LoadableDetachableModel<String>() {
|
||||
|
||||
@Override
|
||||
protected String load() {
|
||||
if (getUserCount() > LicenseDetail.FREE_LICENSE_USERS) {
|
||||
return String.format(""
|
||||
+ "License will expire in %d days. The free %d-user license will take effect "
|
||||
+ "after expiration", licenseDetail.getRemainingDays(), LicenseDetail.FREE_LICENSE_USERS);
|
||||
} else {
|
||||
return String.format("License will expire in %d days, The free %d-user license will take "
|
||||
+ "effect after expiration", licenseDetail.getRemainingDays(),
|
||||
LicenseDetail.FREE_LICENSE_USERS);
|
||||
}
|
||||
}
|
||||
|
||||
}).setVisible(licenseDetail.getRemainingDays()>=0 && licenseDetail.getRemainingDays() < LicenseDetail.ABOUT_TO_EXPIRE_DAYS).setEscapeModelStrings(false));
|
||||
|
||||
String usersInfo = String.format("%d free + %d licensed (<a href=\"https://www.gitplex.com/purchase\">add more</a>)",
|
||||
LicenseDetail.FREE_LICENSE_USERS, licenseDetail.getLicensedUsers());
|
||||
fragment.add(new Label("users", usersInfo).setEscapeModelStrings(false));
|
||||
fragment.add(new Label("issueDate",
|
||||
WebConstants.DATE_FORMATTER.print(new DateTime(licenseDetail.getIssueDate()))));
|
||||
fragment.add(new Label("expirationDate",
|
||||
WebConstants.DATE_FORMATTER.print(new DateTime(licenseDetail.getExpirationDate())) + " (<a href=\"https://www.gitplex.com/purchase\">renew</a>)").setEscapeModelStrings(false));
|
||||
add(fragment);
|
||||
} else {
|
||||
if (getUserCount() > LicenseDetail.FREE_LICENSE_USERS) {
|
||||
String message = String.format(""
|
||||
+ "Free %d-user license. <a href=\"https://www.gitplex.com/purchase\">Add additional users</a>",
|
||||
LicenseDetail.FREE_LICENSE_USERS);
|
||||
add(new Label(LICENSE_DETAIL_ID, message).setEscapeModelStrings(false));
|
||||
} else {
|
||||
String message = String.format(""
|
||||
+ "Free %d-user license. <a href=\"https://www.gitplex.com/purchase\">Add additional users</a>",
|
||||
LicenseDetail.FREE_LICENSE_USERS);
|
||||
add(new Label(LICENSE_DETAIL_ID, message).setEscapeModelStrings(false));
|
||||
}
|
||||
}
|
||||
|
||||
add(new ModalLink("inputLicenseKey") {
|
||||
|
||||
@Override
|
||||
protected Component newContent(String id, ModalPanel modal) {
|
||||
Fragment fragment = new Fragment(id, "licenseKeyInputFrag", LicenseManagementPage.this);
|
||||
licenseKey = null;
|
||||
Form<?> form = new Form<Void>("form");
|
||||
form.add(new TextArea<String>("licenseKey", new IModel<String>() {
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObject() {
|
||||
return licenseKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(String object) {
|
||||
licenseKey = object;
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
NotificationPanel feedback = new NotificationPanel("feedback", fragment);
|
||||
feedback.setOutputMarkupId(true);
|
||||
form.add(feedback);
|
||||
|
||||
form.add(new AjaxButton("ok") {
|
||||
|
||||
@Override
|
||||
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
|
||||
super.onSubmit(target, form);
|
||||
if (licenseKey == null) {
|
||||
error("Please input license key");
|
||||
target.add(feedback);
|
||||
} else {
|
||||
LicenseDetail license = LicenseDetail.decode(licenseKey);
|
||||
if (license == null) {
|
||||
error("Invalid license key");
|
||||
target.add(feedback);
|
||||
} else {
|
||||
GitPlex.getInstance(ConfigManager.class).saveLicense(license);
|
||||
setResponsePage(LicenseManagementPage.class);
|
||||
getSession().success("License key applied successfully");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
form.add(new AjaxLink<Void>("cancel") {
|
||||
|
||||
@Override
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
modal.close();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
form.add(new AjaxLink<Void>("close") {
|
||||
|
||||
@Override
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
modal.close();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
fragment.add(form);
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
String confirmMessage = String.format(""
|
||||
+ "The free-%d user license will take effect after removal. Do you really want to continue?",
|
||||
LicenseDetail.FREE_LICENSE_USERS);
|
||||
add(new Link<Void>("removeLicense") {
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
GitPlex.getInstance(ConfigManager.class).saveLicense(null);
|
||||
setResponsePage(LicenseManagementPage.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(getLicense() != null);
|
||||
}
|
||||
|
||||
}.add(new ConfirmOnClick(confirmMessage)));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private LicenseDetail getLicense() {
|
||||
return licenseModel.getObject();
|
||||
}
|
||||
|
||||
private int getUserCount() {
|
||||
return userCountModel.getObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach() {
|
||||
userCountModel.detach();
|
||||
licenseModel.detach();
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
}
|
||||
@ -26,6 +26,11 @@
|
||||
<div class="help pull-right">
|
||||
<a wicket:id="docLink" title="Help"><i class="fa fa-question"></i></a>
|
||||
</div>
|
||||
<wicket:enclosure child="pushDisabled">
|
||||
<div class="push-disabled pull-right">
|
||||
<span wicket:id="pushDisabled" class="label label-danger">Git Push Disabled</span>
|
||||
</div>
|
||||
</wicket:enclosure>
|
||||
</div>
|
||||
<div class="body">
|
||||
<wicket:child></wicket:child>
|
||||
|
||||
@ -25,9 +25,12 @@ import com.gitplex.launcher.loader.AppLoader;
|
||||
import com.gitplex.launcher.loader.Plugin;
|
||||
import com.gitplex.server.GitPlex;
|
||||
import com.gitplex.server.manager.ConfigManager;
|
||||
import com.gitplex.server.manager.UserManager;
|
||||
import com.gitplex.server.model.User;
|
||||
import com.gitplex.server.persistence.dao.EntityCriteria;
|
||||
import com.gitplex.server.security.SecurityUtils;
|
||||
import com.gitplex.server.web.ComponentRenderer;
|
||||
import com.gitplex.server.web.behavior.TooltipBehavior;
|
||||
import com.gitplex.server.web.component.avatar.AvatarLink;
|
||||
import com.gitplex.server.web.component.floating.AlignPlacement;
|
||||
import com.gitplex.server.web.component.floating.FloatingPanel;
|
||||
@ -43,6 +46,10 @@ import com.gitplex.server.web.page.user.UserProfilePage;
|
||||
import com.gitplex.server.web.websocket.PageDataChanged;
|
||||
import com.gitplex.server.web.websocket.TaskChangedRegion;
|
||||
import com.gitplex.server.web.websocket.WebSocketRegion;
|
||||
import com.gitplex.utils.license.LicenseDetail;
|
||||
|
||||
import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
|
||||
import de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig.Placement;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class LayoutPage extends BasePage {
|
||||
@ -74,7 +81,22 @@ public abstract class LayoutPage extends BasePage {
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
int userCount = GitPlex.getInstance(UserManager.class).count(EntityCriteria.of(User.class));
|
||||
int licenseLimit = LicenseDetail.FREE_LICENSE_USERS;
|
||||
LicenseDetail license = GitPlex.getInstance(ConfigManager.class).getLicense();
|
||||
if (license != null && license.getRemainingDays()>=0)
|
||||
licenseLimit += license.getLicensedUsers();
|
||||
if (userCount > licenseLimit) {
|
||||
String tooltip = String.format(""
|
||||
+ "Git push is disabled as number of users (%d) in system exceeds license limit (%d).",
|
||||
userCount, licenseLimit);
|
||||
TooltipBehavior tooltipBehavior = new TooltipBehavior(Model.of(tooltip),
|
||||
new TooltipConfig().withPlacement(Placement.bottom));
|
||||
head.add(new WebMarkupContainer("pushDisabled").add(tooltipBehavior));
|
||||
} else {
|
||||
head.add(new WebMarkupContainer("pushDisabled").setVisible(false));
|
||||
}
|
||||
head.add(new ExternalLink("docLink", GitPlex.getInstance().getDocLink()));
|
||||
|
||||
User user = getLoginUser();
|
||||
|
||||
@ -13,6 +13,12 @@ html, body {
|
||||
text-decoration: none;
|
||||
color: #CCC;
|
||||
}
|
||||
#main>.head .push-disabled {
|
||||
padding-top: 6px;
|
||||
}
|
||||
#main>.head .push-disabled .label {
|
||||
font-size: 15px;
|
||||
}
|
||||
#main>.head>.logo .fa {
|
||||
font-size: 28px;
|
||||
color: #EEE;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user