Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add profile and configuration class for running bakery in Control Center #1378

Open
wants to merge 8 commits into
base: v24
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM openjdk:21-jdk-slim
COPY target/*.jar ./app.jar
ENTRYPOINT java -jar ./app.jar

30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,36 @@ spring.jpa.hibernate.ddl-auto=update

# Running the Project in Production Mode

`mvn spring-boot:run -Pproduction`
`mvn -Pproduction`

The default mode when the application is built or started is 'development'. The 'production' mode is turned on by enabling the `production` profile when building or starting the app.


# Deploy the application for Production

`mvn package -Pproduction`

Then run it with

`java -jar target/*.jar`


# Deploying the Project in Control Center

Bakery has a profile that allows the application being deployed with [Control Center](https://vaadin.com/docs/latest/control-center)

Compile, package, build the image and upload to docker hub.

```
mvn package -P production -P control-center
docker build -t your_docker_id/bakery:latest .
docker push your_docker_id/bakery:latest
```

Import it in Control Center selecting the `Identity manager` flag. Then create roles `admin`, `baker` and `barista` in Control Center and create the corresponding users to login into bakery application.



# Running in Eclipse or IntelliJ
As both IDEs support running Spring Boot applications you just have to import the project and select `com.vaadin.starter.bakery.Application` as main class if not done automatically. Using an IDE will also allow you to speed up development even more. Just check https://vaadin.com/blog/developing-without-server-restarts.

Expand Down Expand Up @@ -92,6 +118,6 @@ For full terms, see LICENSE
Pro components used in the starter are :
- [Vaadin Crud](https://vaadin.com/components/vaadin-crud)
- [Vaadin Charts](https://vaadin.com/components/vaadin-charts)
- [Vaadin Confirm Dialog](https://vaadin.com/components/vaadin-confirm-dialog)
- [Vaadin Confirm Dialog](https://vaadin.com/components/vaadin-confirm-dialog)

Also the tests are created using [Testbench](https://vaadin.com/testbench) library.
14 changes: 14 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,20 @@
</build>

<profiles>
<profile>
<id>control-center</id>
<properties>
<spring.profiles.active>control-center</spring.profiles.active>
</properties>
<dependencies>
<dependency>
<groupId>com.vaadin</groupId>
<artifactId>control-center-starter</artifactId>
</dependency>
</dependencies>
<build>
</build>
</profile>
<profile>
<!-- Production mode is activated using -Pproduction -->
<id>production</id>
Expand Down
6 changes: 6 additions & 0 deletions src/main/frontend/themes/bakery/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
}
}

.app-name {
font-size:var(--lumo-font-size-xl);
font-weight:bold;
padding-left: 1em
}

.v-loading-indicator,
.v-system-error,
.v-reconnect-dialog {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
package com.vaadin.starter.bakery.app.security;

import com.vaadin.flow.spring.security.VaadinWebSecurity;
import com.vaadin.starter.bakery.backend.data.entity.User;
import com.vaadin.starter.bakery.backend.repositories.UserRepository;
import com.vaadin.starter.bakery.ui.views.login.LoginView;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Scope;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import com.vaadin.flow.spring.security.VaadinWebSecurity;
import com.vaadin.starter.bakery.backend.data.entity.User;
import com.vaadin.starter.bakery.backend.repositories.UserRepository;
import com.vaadin.starter.bakery.ui.views.login.LoginView;

/**
* Configures spring security, doing the following:
* <li>Bypass security checks for static resources,</li>
Expand All @@ -26,16 +25,9 @@
*/
@EnableWebSecurity
@Configuration
@Profile("!control-center")
public class SecurityConfiguration extends VaadinWebSecurity {

/**
* The password encoder to use when encrypting passwords.
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public CurrentUser currentUser(UserRepository userRepository) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.vaadin.starter.bakery.app.security;

import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.Scope;

import com.vaadin.flow.spring.security.AuthenticationContext;
import com.vaadin.starter.bakery.backend.data.entity.User;

/**
* Provide Beans for the control center security context.
* These beans might be removed, but needs important changes in code.
*/
@Configuration
@Profile("control-center")
public class SecurityConfigurationCC {

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
CurrentUser currentUser(AuthenticationContext authCtx) {
User user = new User();
user.setFirstName(authCtx.getPrincipalName().orElse(null));
return () -> user;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
import java.util.Collections;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.vaadin.starter.bakery.backend.data.entity.User;
Expand All @@ -29,6 +32,14 @@ public class UserDetailsServiceImpl implements UserDetailsService {
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}

/**
* The password encoder to use when encrypting passwords.
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

/**
*
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/vaadin/starter/bakery/ui/AppShell.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import static com.vaadin.starter.bakery.ui.utils.BakeryConst.VIEWPORT;

@Viewport(VIEWPORT)
@Theme("bakery")
@Theme(value = "bakery", variant = "dark")
@PWA(name = "Bakery App Starter", shortName = "###Bakery###",
startPath = "login",
backgroundColor = "#227aef", themeColor = "#227aef",
Expand Down
24 changes: 11 additions & 13 deletions src/main/java/com/vaadin/starter/bakery/ui/MainView.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.vaadin.starter.bakery.ui;

import static com.vaadin.flow.i18n.I18NProvider.translate;

import static com.vaadin.starter.bakery.ui.utils.BakeryConst.TITLE_DASHBOARD;
import static com.vaadin.starter.bakery.ui.utils.BakeryConst.TITLE_LOGOUT;
import static com.vaadin.starter.bakery.ui.utils.BakeryConst.TITLE_PRODUCTS;
Expand All @@ -10,11 +12,10 @@
import java.util.List;
import java.util.Optional;

import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasComponents;
import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.applayout.AppLayout;
import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
import com.vaadin.flow.component.html.Anchor;
Expand All @@ -28,23 +29,23 @@
import com.vaadin.flow.server.VaadinServlet;
import com.vaadin.flow.server.VaadinServletRequest;
import com.vaadin.flow.server.auth.AccessAnnotationChecker;
import com.vaadin.starter.bakery.ui.utils.BakeryConst;
import com.vaadin.flow.spring.security.AuthenticationContext;
import com.vaadin.starter.bakery.ui.views.HasConfirmation;
import com.vaadin.starter.bakery.ui.views.admin.products.ProductsView;
import com.vaadin.starter.bakery.ui.views.admin.users.UsersView;
import com.vaadin.starter.bakery.ui.views.dashboard.DashboardView;
import com.vaadin.starter.bakery.ui.views.storefront.StorefrontView;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import jakarta.annotation.PostConstruct;

public class MainView extends AppLayout {

@Autowired
private AccessAnnotationChecker accessChecker;
@Autowired
private AuthenticationContext authenticationContext;
private final ConfirmDialog confirmDialog = new ConfirmDialog();
private Tabs menu;
private static final String LOGOUT_SUCCESS_URL = "/" + BakeryConst.PAGE_ROOT;

@PostConstruct
public void init() {
Expand All @@ -53,7 +54,8 @@ public void init() {
confirmDialog.setCancelButtonTheme("raised tertiary");

this.setDrawerOpened(false);
Span appName = new Span("###Bakery###");
Span appName = new Span(translate("app.title"));
appName.addClassName("app-name");
appName.addClassName("hide-on-mobile");

menu = createMenuTabs();
Expand All @@ -66,11 +68,7 @@ public void init() {

e.getSelectedTab().getId().ifPresent(id -> {
if ("logout-tab".equals(id)) {
UI.getCurrent().getPage().setLocation(LOGOUT_SUCCESS_URL);
SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
logoutHandler.logout(
VaadinServletRequest.getCurrent().getHttpServletRequest(), null,
null);
authenticationContext.logout();
}
});
});
Expand Down Expand Up @@ -155,4 +153,4 @@ private static <T extends HasComponents> T populateLink(T a, VaadinIcon icon, St
a.add(title);
return a;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.vaadin.starter.bakery.ui.views.admin.products;

import static com.vaadin.flow.i18n.I18NProvider.translate;

import com.vaadin.flow.component.crud.BinderCrudEditor;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
Expand Down Expand Up @@ -51,9 +53,9 @@ protected String getBasePage() {
}

private static BinderCrudEditor<Product> createForm() {
TextField name = new TextField("Product name");
TextField name = new TextField(translate("product.name"));
name.getElement().setAttribute("colspan", "2");
TextField price = new TextField("Unit price");
TextField price = new TextField(translate("unit.price"));
price.getElement().setAttribute("colspan", "2");

FormLayout form = new FormLayout(name, price);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.vaadin.starter.bakery.ui.views.admin.users;

import static com.vaadin.flow.i18n.I18NProvider.translate;

import jakarta.annotation.security.RolesAllowed;

import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -53,15 +55,15 @@ protected String getBasePage() {
}

private static BinderCrudEditor<User> createForm(PasswordEncoder passwordEncoder) {
EmailField email = new EmailField("Email (login)");
EmailField email = new EmailField(translate("email.field"));
email.getElement().setAttribute("colspan", "2");
TextField first = new TextField("First name");
TextField last = new TextField("Last name");
PasswordField password = new PasswordField("Password");
TextField first = new TextField(translate("first.name.field"));
TextField last = new TextField(translate("last.name.field"));
PasswordField password = new PasswordField(translate("password.field"));
password.getElement().setAttribute("colspan", "2");
ComboBox<String> role = new ComboBox<>();
role.getElement().setAttribute("colspan", "2");
role.setLabel("Role");
role.setLabel(translate("role.field"));

FormLayout form = new FormLayout(email, first, last, password, role);

Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
[email protected]@
spring.main.allow-bean-definition-overriding=true

server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain,application/javascript,text/css
security.basic.enabled=false
server.tomcat.uri-encoding=UTF-8

spring.jackson.serialization.write_dates_as_timestamps=false
# Comment out if using anything else than H2 (e.g. MySQL or PostgreSQL)
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
Expand All @@ -17,3 +21,4 @@ logging.level.org.atmosphere = warn

# Ensure application is run in Vaadin 14/npm mode
vaadin.compatibilityMode = false

8 changes: 8 additions & 0 deletions src/main/resources/vaadin-i18n/translations.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
app.title=Bakery
product.name=Product name
unit.price=Unit price
email.field=Email (login)
first.name.field=First name
last.name.field=Last name
password.field=Password
role.field=Role
Loading