[REPO REFACTOR]: changed to a better git repository structure with branches

This commit is contained in:
2025-10-31 03:32:24 +01:00
parent ad689049d5
commit 8360c7e8e0
212 changed files with 15955 additions and 0 deletions

View File

@@ -0,0 +1 @@
/target/

View File

@@ -0,0 +1,55 @@
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.miarma.api</groupId>
<artifactId>huertosdecine</artifactId>
<version>1.2.0</version>
<properties>
<maven.compiler.source>23</maven.compiler.source>
<maven.compiler.target>23</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>MiarmaGit</id>
<url>https://git.miarma.net/api/packages/Gallardo7761/maven</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>net.miarma.api</groupId>
<artifactId>backlib</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
<build>
<finalName>ME-HuertosDeCine</finalName>
<plugins>
<!-- Maven Shade Plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>net.miarma.api.microservices.huertosdecine.CineMainVerticle</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,155 @@
package net.miarma.api.microservices.huertosdecine.dao;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.db.DataAccessObject;
import net.miarma.api.backlib.db.DatabaseManager;
import net.miarma.api.backlib.db.QueryBuilder;
import net.miarma.api.backlib.http.QueryFilters;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.entities.MovieEntity;
import java.util.List;
import java.util.Map;
public class MovieDAO implements DataAccessObject<MovieEntity, Integer> {
private final DatabaseManager db;
public MovieDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<MovieEntity>> getAll() {
return getAll(new QueryParams(Map.of(), new QueryFilters()));
}
@Override
public Future<MovieEntity> getById(Integer id) {
Promise<MovieEntity> promise = Promise.promise();
String query = QueryBuilder
.select(MovieEntity.class)
.where(Map.of("movie_id", id.toString()))
.build();
db.executeOne(query, MovieEntity.class,
promise::complete,
promise::fail
);
return promise.future();
}
public Future<List<MovieEntity>> getAll(QueryParams params) {
Promise<List<MovieEntity>> promise = Promise.promise();
String query = QueryBuilder
.select(MovieEntity.class)
.where(params.getFilters())
.orderBy(params.getQueryFilters().getSort(), params.getQueryFilters().getOrder())
.limit(params.getQueryFilters().getLimit())
.offset(params.getQueryFilters().getOffset())
.build();
db.execute(query, MovieEntity.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<MovieEntity> insert(MovieEntity movieEntity) {
Promise<MovieEntity> promise = Promise.promise();
String query = QueryBuilder
.insert(movieEntity)
.build();
db.executeOne(query, MovieEntity.class,
_ -> promise.complete(movieEntity),
promise::fail
);
return promise.future();
}
@Override
public Future<MovieEntity> upsert(MovieEntity movieEntity, String... conflictKeys) {
Promise<MovieEntity> promise = Promise.promise();
String query = QueryBuilder
.upsert(movieEntity, conflictKeys)
.build();
db.executeOne(query, MovieEntity.class,
_ -> promise.complete(movieEntity),
promise::fail
);
return promise.future();
}
@Override
public Future<MovieEntity> update(MovieEntity movieEntity) {
Promise<MovieEntity> promise = Promise.promise();
String query = QueryBuilder
.update(movieEntity)
.build();
db.executeOne(query, MovieEntity.class,
_ -> promise.complete(movieEntity),
promise::fail
);
return promise.future();
}
public Future<MovieEntity> updateWithNulls(MovieEntity movieEntity) {
Promise<MovieEntity> promise = Promise.promise();
String query = QueryBuilder
.updateWithNulls(movieEntity)
.build();
db.executeOne(query, MovieEntity.class,
_ -> promise.complete(movieEntity),
promise::fail
);
return promise.future();
}
@Override
public Future<Boolean> delete(Integer id) {
Promise<Boolean> promise = Promise.promise();
MovieEntity movieEntity = new MovieEntity();
movieEntity.setMovie_id(id);
String query = QueryBuilder
.delete(movieEntity)
.build();
db.executeOne(query, MovieEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
@Override
public Future<Boolean> exists(Integer id) {
Promise<Boolean> promise = Promise.promise();
String query = QueryBuilder
.select(MovieEntity.class)
.where( Map.of("movie_id", id.toString()))
.build();
db.executeOne(query, MovieEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,151 @@
package net.miarma.api.microservices.huertosdecine.dao;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.db.DataAccessObject;
import net.miarma.api.backlib.db.DatabaseManager;
import net.miarma.api.backlib.db.QueryBuilder;
import net.miarma.api.backlib.http.QueryFilters;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.entities.UserMetadataEntity;
import java.util.List;
import java.util.Map;
public class UserMetadataDAO implements DataAccessObject<UserMetadataEntity, Integer> {
private final DatabaseManager db;
public UserMetadataDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<UserMetadataEntity>> getAll() {
return getAll(new QueryParams(Map.of(), new QueryFilters()));
}
@Override
public Future<UserMetadataEntity> getById(Integer id) {
Promise<UserMetadataEntity> promise = Promise.promise();
String query = QueryBuilder
.select(UserMetadataEntity.class)
.where(Map.of("user_id", id.toString()))
.build();
db.executeOne(query, UserMetadataEntity.class,
promise::complete,
promise::fail
);
return promise.future();
}
public Future<List<UserMetadataEntity>> getAll(QueryParams params) {
Promise<List<UserMetadataEntity>> promise = Promise.promise();
String query = QueryBuilder
.select(UserMetadataEntity.class)
.where(params.getFilters())
.orderBy(params.getQueryFilters().getSort(), params.getQueryFilters().getOrder())
.limit(params.getQueryFilters().getLimit())
.offset(params.getQueryFilters().getOffset())
.build();
db.execute(query, UserMetadataEntity.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<UserMetadataEntity> insert(UserMetadataEntity metadata) {
Promise<UserMetadataEntity> promise = Promise.promise();
String query = QueryBuilder
.insert(metadata)
.build();
db.executeOne(query, UserMetadataEntity.class,
_ -> promise.complete(),
promise::fail
);
return promise.future();
}
@Override
public Future<UserMetadataEntity> upsert(UserMetadataEntity metadata, String... conflictKeys) {
Promise<UserMetadataEntity> promise = Promise.promise();
String query = QueryBuilder
.upsert(metadata, conflictKeys)
.build();
db.executeOne(query, UserMetadataEntity.class,
_ -> promise.complete(metadata),
promise::fail
);
return promise.future();
}
@Override
public Future<UserMetadataEntity> update(UserMetadataEntity metadata) {
Promise<UserMetadataEntity> promise = Promise.promise();
String query = QueryBuilder
.update(metadata)
.build();
db.executeOne(query, UserMetadataEntity.class,
_ -> promise.complete(metadata),
promise::fail
);
return promise.future();
}
public Future<UserMetadataEntity> updateWithNulls(UserMetadataEntity metadata) {
Promise<UserMetadataEntity> promise = Promise.promise();
String query = QueryBuilder.updateWithNulls(metadata).build();
db.executeOne(query, UserMetadataEntity.class,
_ -> promise.complete(metadata),
promise::fail
);
return promise.future();
}
@Override
public Future<Boolean> delete(Integer id) {
Promise<Boolean> promise = Promise.promise();
UserMetadataEntity metadata = new UserMetadataEntity();
metadata.setUser_id(id);
String query = QueryBuilder.delete(metadata).build();
db.executeOne(query, UserMetadataEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
@Override
public Future<Boolean> exists(Integer id) {
Promise<Boolean> promise = Promise.promise();
String query = QueryBuilder
.select(UserMetadataEntity.class)
.where(Map.of("user_id", id.toString()))
.build();
db.executeOne(query, UserMetadataEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,98 @@
package net.miarma.api.microservices.huertosdecine.dao;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.db.DataAccessObject;
import net.miarma.api.backlib.db.DatabaseManager;
import net.miarma.api.backlib.db.QueryBuilder;
import net.miarma.api.backlib.http.QueryFilters;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.entities.ViewerEntity;
import java.util.List;
import java.util.Map;
public class ViewerDAO implements DataAccessObject<ViewerEntity, Integer> {
private final DatabaseManager db;
public ViewerDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<ViewerEntity>> getAll() {
return getAll(new QueryParams(Map.of(), new QueryFilters()));
}
@Override
public Future<ViewerEntity> getById(Integer id) {
Promise<ViewerEntity> promise = Promise.promise();
String query = QueryBuilder
.select(ViewerEntity.class)
.where(Map.of("user_id", id.toString()))
.build();
db.executeOne(query, ViewerEntity.class,
promise::complete,
promise::fail
);
return promise.future();
}
public Future<List<ViewerEntity>> getAll(QueryParams params) {
Promise<List<ViewerEntity>> promise = Promise.promise();
String query = QueryBuilder
.select(ViewerEntity.class)
.where(params.getFilters())
.orderBy(params.getQueryFilters().getSort(), params.getQueryFilters().getOrder())
.limit(params.getQueryFilters().getLimit())
.offset(params.getQueryFilters().getOffset())
.build();
db.execute(query, ViewerEntity.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<ViewerEntity> insert(ViewerEntity viewerEntity) {
throw new UnsupportedOperationException("Insert not supported on view-based DAO");
}
@Override
public Future<ViewerEntity> upsert(ViewerEntity viewer, String... conflictKeys) {
throw new UnsupportedOperationException("Upsert not supported on view-based DAO");
}
@Override
public Future<ViewerEntity> update(ViewerEntity viewerEntity) {
throw new UnsupportedOperationException("Update not supported on view-based DAO");
}
@Override
public Future<Boolean> delete(Integer id) {
throw new UnsupportedOperationException("Delete not supported on view-based DAO");
}
@Override
public Future<Boolean> exists(Integer integer) {
Promise<Boolean> promise = Promise.promise();
String query = QueryBuilder
.select(ViewerEntity.class)
.where(Map.of("user_id", integer.toString()))
.build();
db.executeOne(query, ViewerEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,185 @@
package net.miarma.api.microservices.huertosdecine.dao;
import io.vertx.core.Future;
import io.vertx.core.Promise;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.db.DataAccessObject;
import net.miarma.api.backlib.db.DatabaseManager;
import net.miarma.api.backlib.db.QueryBuilder;
import net.miarma.api.backlib.http.QueryFilters;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.entities.VoteEntity;
import java.util.List;
import java.util.Map;
public class VoteDAO implements DataAccessObject<VoteEntity, Integer> {
private final DatabaseManager db;
public VoteDAO(Pool pool) {
this.db = DatabaseManager.getInstance(pool);
}
@Override
public Future<List<VoteEntity>> getAll() {
return getAll(new QueryParams(Map.of(), new QueryFilters()));
}
@Override
public Future<VoteEntity> getById(Integer integer) {
Promise<VoteEntity> promise = Promise.promise();
String query = QueryBuilder
.select(VoteEntity.class)
.where(Map.of("movie_id", integer.toString()))
.build();
db.executeOne(query, VoteEntity.class,
promise::complete,
promise::fail
);
return promise.future();
}
public Future<List<VoteEntity>> getAll(QueryParams params) {
Promise<List<VoteEntity>> promise = Promise.promise();
String query = QueryBuilder
.select(VoteEntity.class)
.where(params.getFilters())
.orderBy(params.getQueryFilters().getSort(), params.getQueryFilters().getOrder())
.limit(params.getQueryFilters().getLimit())
.offset(params.getQueryFilters().getOffset())
.build();
db.execute(query, VoteEntity.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
public Future<List<VoteEntity>> getVotesByMovieId(Integer movieId) {
Promise<List<VoteEntity>> promise = Promise.promise();
String query = QueryBuilder
.select(VoteEntity.class)
.where(Map.of("movie_id", movieId.toString()))
.build();
db.execute(query, VoteEntity.class,
list -> promise.complete(list.isEmpty() ? List.of() : list),
promise::fail
);
return promise.future();
}
@Override
public Future<VoteEntity> insert(VoteEntity voteEntity) {
Promise<VoteEntity> promise = Promise.promise();
String query = QueryBuilder
.insert(voteEntity)
.build();
db.executeOne(query, VoteEntity.class,
_ -> promise.complete(voteEntity),
promise::fail
);
return promise.future();
}
@Override
public Future<VoteEntity> upsert(VoteEntity voteEntity, String... conflictKeys) {
Promise<VoteEntity> promise = Promise.promise();
String query = QueryBuilder
.upsert(voteEntity, conflictKeys)
.build();
db.executeOne(query, VoteEntity.class,
_ -> promise.complete(voteEntity),
promise::fail
);
return promise.future();
}
public Future<VoteEntity> upsert(VoteEntity voteEntity) {
Promise<VoteEntity> promise = Promise.promise();
String query = QueryBuilder
.upsert(voteEntity, "user_id", "movie_id")
.build();
db.executeOne(query, VoteEntity.class,
_ -> promise.complete(voteEntity),
promise::fail
);
return promise.future();
}
@Override
public Future<VoteEntity> update(VoteEntity voteEntity) {
Promise<VoteEntity> promise = Promise.promise();
String query = QueryBuilder
.update(voteEntity)
.build();
db.executeOne(query, VoteEntity.class,
_ -> promise.complete(voteEntity),
promise::fail
);
return promise.future();
}
public Future<VoteEntity> updateWithNulls(VoteEntity voteEntity) {
Promise<VoteEntity> promise = Promise.promise();
String query = QueryBuilder
.updateWithNulls(voteEntity)
.build();
db.executeOne(query, VoteEntity.class,
_ -> promise.complete(voteEntity),
promise::fail
);
return promise.future();
}
@Override
public Future<Boolean> delete(Integer id) {
Promise<Boolean> promise = Promise.promise();
VoteEntity voteEntity = new VoteEntity();
voteEntity.setMovie_id(id);
String query = QueryBuilder
.delete(voteEntity)
.build();
db.executeOne(query, VoteEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
@Override
public Future<Boolean> exists(Integer integer) {
Promise<Boolean> promise = Promise.promise();
String query = QueryBuilder
.select(VoteEntity.class)
.where(Map.of("movie_id", integer.toString()))
.build();
db.executeOne(query, VoteEntity.class,
result -> promise.complete(result != null),
promise::fail
);
return promise.future();
}
}

View File

@@ -0,0 +1,53 @@
package net.miarma.api.microservices.huertosdecine.entities;
import io.vertx.sqlclient.Row;
import net.miarma.api.backlib.annotations.Table;
import net.miarma.api.backlib.db.AbstractEntity;
@Table("cine_movies")
public class MovieEntity extends AbstractEntity {
private Integer movie_id;
private String title;
private String description;
private String cover;
public MovieEntity() {
super();
}
public MovieEntity(Row row) {
super(row);
}
public Integer getMovie_id() {
return movie_id;
}
public void setMovie_id(Integer movie_id) {
this.movie_id = movie_id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
}

View File

@@ -0,0 +1,65 @@
package net.miarma.api.microservices.huertosdecine.entities;
import io.vertx.sqlclient.Row;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.annotations.Table;
import net.miarma.api.backlib.db.AbstractEntity;
import java.time.LocalDateTime;
@Table("cine_user_metadata")
public class UserMetadataEntity extends AbstractEntity {
private Integer user_id;
private Constants.CineUserStatus status;
private Constants.CineUserRole role;
private LocalDateTime created_at;
public UserMetadataEntity() {
super();
}
public UserMetadataEntity(Row row) {
super(row);
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public Constants.CineUserStatus getStatus() {
return status;
}
public void setStatus(Constants.CineUserStatus status) {
this.status = status;
}
public Constants.CineUserRole getRole() {
return role;
}
public void setRole(Constants.CineUserRole role) {
this.role = role;
}
public LocalDateTime getCreated_at() {
return created_at;
}
public void setCreated_at(LocalDateTime created_at) {
this.created_at = created_at;
}
public static UserMetadataEntity fromViewerEntity(ViewerEntity viewer) {
UserMetadataEntity metadata = new UserMetadataEntity();
metadata.setUser_id(viewer.getUser_id());
metadata.setStatus(viewer.getStatus());
metadata.setRole(viewer.getRole());
metadata.setCreated_at(viewer.getCreated_at());
return metadata;
}
}

View File

@@ -0,0 +1,135 @@
package net.miarma.api.microservices.huertosdecine.entities;
import java.time.LocalDateTime;
import io.vertx.sqlclient.Row;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.annotations.APIDontReturn;
import net.miarma.api.backlib.annotations.Table;
import net.miarma.api.backlib.db.AbstractEntity;
import net.miarma.api.backlib.interfaces.IUser;
@Table("v_cine_viewers")
public class ViewerEntity extends AbstractEntity implements IUser {
private Integer user_id;
private String user_name;
private String email;
private String display_name;
@APIDontReturn
private String password;
private String avatar;
private Constants.CineUserStatus status;
private Constants.CineUserRole role;
private Constants.CoreUserGlobalStatus global_status;
private Constants.CoreUserRole global_role;
private LocalDateTime created_at;
public ViewerEntity() {
super();
}
public ViewerEntity(Row row) {
super(row);
}
public ViewerEntity(IUser user, UserMetadataEntity metadata) {
this.user_id = user.getUser_id();
this.user_name = user.getUser_name();
this.email = user.getEmail();
this.display_name = user.getDisplay_name();
this.password = user.getPassword();
this.avatar = user.getAvatar();
this.status = metadata.getStatus();
this.role = metadata.getRole();
this.global_status = user.getGlobal_status();
this.global_role = user.getGlobal_role();
}
public Integer getUser_id() {
return user_id;
}
public void setUser_id(Integer user_id) {
this.user_id = user_id;
}
public String getUser_name() {
return user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getDisplay_name() {
return display_name;
}
public void setDisplay_name(String display_name) {
this.display_name = display_name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getAvatar() {
return avatar;
}
public void setAvatar(String avatar) {
this.avatar = avatar;
}
public Constants.CineUserStatus getStatus() {
return status;
}
public void setStatus(Constants.CineUserStatus status) {
this.status = status;
}
public Constants.CineUserRole getRole() {
return role;
}
public void setRole(Constants.CineUserRole role) {
this.role = role;
}
public Constants.CoreUserGlobalStatus getGlobal_status() {
return global_status;
}
public void setGlobal_status(Constants.CoreUserGlobalStatus global_status) {
this.global_status = global_status;
}
public Constants.CoreUserRole getGlobal_role() {
return global_role;
}
public void setGlobal_role(Constants.CoreUserRole global_role) {
this.global_role = global_role;
}
public LocalDateTime getCreated_at() {
return created_at;
}
public void setCreated_at(LocalDateTime created_at) {
this.created_at = created_at;
}
}

View File

@@ -0,0 +1,31 @@
package net.miarma.api.microservices.huertosdecine.entities;
import io.vertx.sqlclient.Row;
import net.miarma.api.backlib.annotations.Table;
import net.miarma.api.backlib.db.AbstractEntity;
import java.time.LocalDateTime;
@Table("cine_votes")
public class VoteEntity extends AbstractEntity {
private Integer user_id;
private Integer movie_id;
private Integer vote;
private LocalDateTime voted_at;
public VoteEntity() { super(); }
public VoteEntity(Row row) { super(row); }
public Integer getUser_id() { return user_id; }
public void setUser_id(Integer user_id) { this.user_id = user_id; }
public Integer getMovie_id() { return movie_id; }
public void setMovie_id(Integer movie_id) { this.movie_id = movie_id; }
public Integer getVote() { return vote; }
public void setVote(Integer vote) { this.vote = vote; }
public LocalDateTime getVoted_at() { return voted_at; }
public void setVoted_at(LocalDateTime voted_at) { this.voted_at = voted_at; }
}

View File

@@ -0,0 +1,97 @@
package net.miarma.api.microservices.huertosdecine.handlers;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.ConfigManager;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.http.ApiStatus;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.entities.MovieEntity;
import net.miarma.api.microservices.huertosdecine.services.MovieService;
import net.miarma.api.backlib.util.JsonUtil;
import java.nio.file.Path;
import java.nio.file.Paths;
public class MovieDataHandler {
private final MovieService movieService;
public MovieDataHandler(Pool pool) {
this.movieService = new MovieService(pool);
}
public void getAll(RoutingContext ctx) {
QueryParams params = QueryParams.from(ctx);
movieService.getAll(params)
.onSuccess(movies -> JsonUtil.sendJson(ctx, ApiStatus.OK, movies))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void getById(RoutingContext ctx) {
Integer movieId = Integer.parseInt(ctx.pathParam("movie_id"));
movieService.getById(movieId)
.onSuccess(movie -> JsonUtil.sendJson(ctx, ApiStatus.OK, movie))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void create(RoutingContext ctx) {
MovieEntity movie = Constants.GSON.fromJson(ctx.body().asString(), MovieEntity.class);
movieService.create(movie)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.CREATED, result))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void update(RoutingContext ctx) {
MovieEntity movieFromBody = Constants.GSON.fromJson(ctx.body().asString(), MovieEntity.class);
movieService.getById(movieFromBody.getMovie_id())
.onSuccess(existingMovie -> {
String newCover = movieFromBody.getCover();
String oldCover = existingMovie.getCover();
if (newCover != null && !newCover.isEmpty() && !newCover.equals(oldCover)) {
String cineFiles = ConfigManager.getInstance().getFilesDir("cine");
String filename = Paths.get(existingMovie.getCover()).getFileName().toString();
Path fullPath = Paths.get(cineFiles, filename);
ctx.vertx().fileSystem().delete(fullPath.toString(), fileRes -> {
if (fileRes.failed()) {
Constants.LOGGER.warn("No se pudo eliminar el archivo de portada: {}", fullPath, fileRes.cause());
}
movieService.update(movieFromBody)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.NO_CONTENT, null))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
});
} else {
movieService.update(movieFromBody)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.NO_CONTENT, null))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
})
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.NOT_FOUND, null, "Película no encontrada"));
}
public void delete(RoutingContext ctx) {
Integer movieId = Integer.parseInt(ctx.pathParam("movie_id"));
movieService.getById(movieId).onSuccess(movie -> {
String cineFiles = ConfigManager.getInstance().getFilesDir("cine");
String filename = Paths.get(movie.getCover()).getFileName().toString();
Path fullPath = Paths.get(cineFiles, filename);
ctx.vertx().fileSystem().delete(fullPath.toString(), fileRes -> {
if (fileRes.failed()) {
Constants.LOGGER.warn("No se pudo eliminar el archivo de portada: {}", fullPath, fileRes.cause());
}
movieService.delete(movieId)
.onSuccess(_ -> JsonUtil.sendJson(ctx, ApiStatus.NO_CONTENT, null))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
});
}).onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
}

View File

@@ -0,0 +1,68 @@
package net.miarma.api.microservices.huertosdecine.handlers;
import io.vertx.ext.web.RoutingContext;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.http.ApiStatus;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.entities.UserMetadataEntity;
import net.miarma.api.microservices.huertosdecine.entities.ViewerEntity;
import net.miarma.api.microservices.huertosdecine.services.ViewerService;
import net.miarma.api.backlib.util.JsonUtil;
public class ViewerDataHandler {
private final ViewerService viewerService;
public ViewerDataHandler(Pool pool) {
this.viewerService = new ViewerService(pool);
}
public void getAll(RoutingContext ctx) {
QueryParams params = QueryParams.from(ctx);
viewerService.getAll(params)
.onSuccess(viewers -> JsonUtil.sendJson(ctx, ApiStatus.OK, viewers))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void getById(RoutingContext ctx) {
Integer viewerId = Integer.parseInt(ctx.pathParam("viewer_id"));
viewerService.getById(viewerId)
.onSuccess(viewer -> JsonUtil.sendJson(ctx, ApiStatus.OK, viewer))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void create(RoutingContext ctx) {
ViewerEntity viewer = Constants.GSON.fromJson(ctx.body().asString(), ViewerEntity.class);
viewerService.create(viewer)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.CREATED, result))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void createMetadata(RoutingContext ctx) {
UserMetadataEntity userMetadata = Constants.GSON.fromJson(ctx.body().asString(), UserMetadataEntity.class);
viewerService.createMetadata(userMetadata)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.CREATED, result))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void update(RoutingContext ctx) {
ViewerEntity viewer = Constants.GSON.fromJson(ctx.body().asString(), ViewerEntity.class);
viewerService.update(viewer)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.NO_CONTENT, null))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
public void delete(RoutingContext ctx) {
Integer viewerId = Integer.parseInt(ctx.pathParam("user_id"));
viewerService.delete(viewerId)
.onSuccess(result -> JsonUtil.sendJson(ctx, ApiStatus.NO_CONTENT, null))
.onFailure(err -> JsonUtil.sendJson(ctx, ApiStatus.fromException(err), null, err.getMessage()));
}
}

View File

@@ -0,0 +1,47 @@
package net.miarma.api.microservices.huertosdecine.handlers;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.http.ApiStatus;
import net.miarma.api.backlib.util.EventBusUtil;
import net.miarma.api.backlib.util.JsonUtil;
public class ViewerLogicHandler {
private final Vertx vertx;
public ViewerLogicHandler(Vertx vertx) {
this.vertx = vertx;
}
public void getVotesOnMovieByUserId(RoutingContext ctx) {
Integer movieId = Integer.parseInt(ctx.request().getParam("movie_id"));
Integer userId = Integer.parseInt(ctx.request().getParam("viewer_id"));
JsonObject request = new JsonObject().put("action", "getVotesOnMovieByUserId").put("user_id", userId).put("movie_id", movieId);
vertx.eventBus().request(Constants.CINE_EVENT_BUS, request, ar -> {
if (ar.succeeded()) JsonUtil.sendJson(ctx, ApiStatus.OK, ar.result().body());
else EventBusUtil.handleReplyError(ctx, ar.cause(), "No votes found for this movie and viewer");
});
}
public void login(RoutingContext ctx) {
JsonObject body = ctx.body().asJsonObject();
JsonObject request = new JsonObject()
.put("action", "login")
.put("email", body.getString("email", null))
.put("userName", body.getString("userName", null))
.put("password", body.getString("password"))
.put("keepLoggedIn", body.getBoolean("keepLoggedIn", false));
vertx.eventBus().request(Constants.CINE_EVENT_BUS, request, ar -> {
if (ar.succeeded()) {
JsonObject result = (JsonObject) ar.result().body();
result.put("tokenTime", System.currentTimeMillis());
JsonUtil.sendJson(ctx, ApiStatus.OK, result);
} else {
EventBusUtil.handleReplyError(ctx, ar.cause(), "The viewer is inactive or banned");
}
});
}
}

View File

@@ -0,0 +1,61 @@
package net.miarma.api.microservices.huertosdecine.handlers;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.RoutingContext;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.http.ApiStatus;
import net.miarma.api.microservices.huertosdecine.entities.VoteEntity;
import net.miarma.api.backlib.util.EventBusUtil;
import net.miarma.api.backlib.util.JsonUtil;
public class VoteLogicHandler {
private final Vertx vertx;
public VoteLogicHandler(Vertx vertx) {
this.vertx = vertx;
}
public void getVotes(RoutingContext ctx) {
Integer movieId = Integer.parseInt(ctx.request().getParam("movie_id"));
JsonObject request = new JsonObject().put("action", "getVotes").put("movie_id", movieId);
vertx.eventBus().request(Constants.CINE_EVENT_BUS, request, ar -> {
if (ar.succeeded()) JsonUtil.sendJson(ctx, ApiStatus.OK, ar.result().body());
else EventBusUtil.handleReplyError(ctx, ar.cause(), "No votes found for this movie and viewer");
});
}
public void addVote(RoutingContext ctx) {
Integer movieId = Integer.parseInt(ctx.request().getParam("movie_id"));
VoteEntity vote = Constants.GSON.fromJson(ctx.body().asString(), VoteEntity.class);
JsonObject request = new JsonObject()
.put("action", "addVote")
.put("user_id", vote.getUser_id())
.put("movie_id", movieId)
.put("vote", vote.getVote());
vertx.eventBus().request(Constants.CINE_EVENT_BUS, request, ar -> {
if (ar.succeeded()) JsonUtil.sendJson(ctx, ApiStatus.CREATED, ar.result().body());
else EventBusUtil.handleReplyError(ctx, ar.cause(), "Error adding vote for this movie");
});
}
public void deleteVote(RoutingContext ctx) {
VoteEntity vote = Constants.GSON.fromJson(ctx.body().asString(), VoteEntity.class);
JsonObject request = new JsonObject()
.put("action", "deleteVote")
.put("user_id", vote.getUser_id());
vertx.eventBus().request(Constants.CINE_EVENT_BUS, request, ar -> {
if (ar.succeeded()) JsonUtil.sendJson(ctx, ApiStatus.NO_CONTENT, null);
else EventBusUtil.handleReplyError(ctx, ar.cause(), "Error deleting vote for this movie");
});
}
public void getVoteSelf(RoutingContext ctx) {
String token = ctx.request().getHeader("Authorization").substring("Bearer ".length());
JsonObject request = new JsonObject().put("action", "getVoteSelf").put("token", token);
vertx.eventBus().request(Constants.CINE_EVENT_BUS, request, ar -> {
if (ar.succeeded()) JsonUtil.sendJson(ctx, ApiStatus.OK, ar.result().body());
else EventBusUtil.handleReplyError(ctx, ar.cause(), "No vote found for this viewer");
});
}
}

View File

@@ -0,0 +1,39 @@
package net.miarma.api.microservices.huertosdecine.routing;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.Constants.CineUserRole;
import net.miarma.api.backlib.http.ApiResponse;
import net.miarma.api.backlib.http.ApiStatus;
import net.miarma.api.backlib.security.SusPather;
import net.miarma.api.microservices.huertosdecine.handlers.MovieDataHandler;
import net.miarma.api.microservices.huertosdecine.handlers.ViewerDataHandler;
import net.miarma.api.microservices.huertosdecine.routing.middlewares.CineAuthGuard;
import net.miarma.api.microservices.huertosdecine.services.ViewerService;
public class CineDataRouter {
public static void mount(Router router, Vertx vertx, Pool pool) {
MovieDataHandler hMovieData = new MovieDataHandler(pool);
ViewerDataHandler hViewerData = new ViewerDataHandler(pool);
ViewerService viewerService = new ViewerService(pool);
CineAuthGuard authGuard = new CineAuthGuard(viewerService);
router.route().handler(BodyHandler.create());
router.get(CineEndpoints.MOVIES).handler(authGuard.check()).handler(hMovieData::getAll);
router.get(CineEndpoints.MOVIE).handler(authGuard.check()).handler(hMovieData::getById);
router.post(CineEndpoints.MOVIES).handler(authGuard.check(CineUserRole.ADMIN)).handler(hMovieData::create);
router.put(CineEndpoints.MOVIE).handler(authGuard.check(CineUserRole.ADMIN)).handler(hMovieData::update);
router.delete(CineEndpoints.MOVIE).handler(authGuard.check(CineUserRole.ADMIN)).handler(hMovieData::delete);
router.get(CineEndpoints.VIEWERS).handler(authGuard.check(CineUserRole.ADMIN)).handler(hViewerData::getAll);
router.get(CineEndpoints.VIEWER).handler(authGuard.check(CineUserRole.ADMIN)).handler(hViewerData::getById);
router.post(CineEndpoints.VIEWERS).handler(authGuard.check(CineUserRole.ADMIN)).handler(hViewerData::create);
router.put(CineEndpoints.VIEWER).handler(authGuard.check(CineUserRole.ADMIN)).handler(hViewerData::update);
router.delete(CineEndpoints.VIEWER).handler(authGuard.check(CineUserRole.ADMIN)).handler(hViewerData::delete);
router.post(CineEndpoints.VIEWER_METADATA).handler(authGuard.check(CineUserRole.ADMIN)).handler(hViewerData::createMetadata);
}
}

View File

@@ -0,0 +1,20 @@
package net.miarma.api.microservices.huertosdecine.routing;
import net.miarma.api.backlib.Constants;
public class CineEndpoints {
/* OK */ public static final String LOGIN = Constants.CINE_PREFIX + "/login";
/* OK */ public static final String MOVIES = Constants.CINE_PREFIX + "/movies"; // GET, POST
/* OK */ public static final String MOVIE = Constants.CINE_PREFIX + "/movies/:movie_id"; // GET, PUT, DELETE
/* OK */ public static final String VIEWERS = Constants.CINE_PREFIX + "/viewers"; // GET, POST, PUT, DELETE
/* OK */ public static final String VIEWER = Constants.CINE_PREFIX + "/viewers/:viewer_id"; // GET, PUT, DELETE
public static final String VIEWER_METADATA = Constants.CINE_PREFIX + "/viewers/metadata"; // POST, (PUT)
// logic layer
/* OK */ public static final String MOVIE_VOTES = Constants.CINE_PREFIX + "/movies/:movie_id/votes"; // GET, POST, PUT, DELETE
/* OK */ public static final String SELF_VOTES = Constants.CINE_PREFIX + "/movies/votes/self"; // GET
/* OK */ public static final String VIEWER_VOTES_BY_MOVIE = Constants.CINE_PREFIX + "/viewers/:viewer_id/votes/:movie_id"; // GET
}

View File

@@ -0,0 +1,32 @@
package net.miarma.api.microservices.huertosdecine.routing;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.http.ApiResponse;
import net.miarma.api.backlib.http.ApiStatus;
import net.miarma.api.backlib.security.SusPather;
import net.miarma.api.microservices.huertosdecine.handlers.ViewerLogicHandler;
import net.miarma.api.microservices.huertosdecine.handlers.VoteLogicHandler;
import net.miarma.api.microservices.huertosdecine.routing.middlewares.CineAuthGuard;
import net.miarma.api.microservices.huertosdecine.services.ViewerService;
public class CineLogicRouter {
public static void mount(Router router, Vertx vertx, Pool pool) {
ViewerLogicHandler hViewerLogic = new ViewerLogicHandler(vertx);
VoteLogicHandler hVoteLogic = new VoteLogicHandler(vertx);
ViewerService viewerService = new ViewerService(pool);
CineAuthGuard authGuard = new CineAuthGuard(viewerService);
router.route().handler(BodyHandler.create());
router.post(CineEndpoints.LOGIN).handler(hViewerLogic::login);
router.get(CineEndpoints.VIEWER_VOTES_BY_MOVIE).handler(authGuard.check()).handler(hViewerLogic::getVotesOnMovieByUserId);
router.get(CineEndpoints.MOVIE_VOTES).handler(authGuard.check()).handler(hVoteLogic::getVotes);
router.post(CineEndpoints.MOVIE_VOTES).handler(authGuard.check()).handler(hVoteLogic::addVote);
router.delete(CineEndpoints.MOVIE_VOTES).handler(authGuard.check()).handler(hVoteLogic::deleteVote);
router.get(CineEndpoints.SELF_VOTES).handler(authGuard.check()).handler(hVoteLogic::getVoteSelf);
}
}

View File

@@ -0,0 +1,35 @@
package net.miarma.api.microservices.huertosdecine.routing.middlewares;
import java.util.function.Consumer;
import io.vertx.ext.web.RoutingContext;
import net.miarma.api.backlib.Constants.CineUserRole;
import net.miarma.api.backlib.middlewares.AbstractAuthGuard;
import net.miarma.api.microservices.huertosdecine.entities.ViewerEntity;
import net.miarma.api.microservices.huertosdecine.services.ViewerService;
public class CineAuthGuard extends AbstractAuthGuard<ViewerEntity, CineUserRole> {
private final ViewerService viewerService;
public CineAuthGuard(ViewerService viewerService) {
this.viewerService = viewerService;
}
@Override
protected CineUserRole parseRole(String roleStr) {
return CineUserRole.valueOf(roleStr.toUpperCase());
}
@Override
protected void getUserEntity(int userId, RoutingContext ctx, Consumer<ViewerEntity> callback) {
viewerService.getById(userId).onComplete(ar -> {
if (ar.succeeded()) callback.accept(ar.result());
else callback.accept(null);
});
}
@Override
protected boolean hasPermission(ViewerEntity user, CineUserRole role) {
return user.getRole() == CineUserRole.ADMIN;
}
}

View File

@@ -0,0 +1,53 @@
package net.miarma.api.microservices.huertosdecine.services;
import io.vertx.core.Future;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.exceptions.NotFoundException;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.microservices.huertosdecine.dao.MovieDAO;
import net.miarma.api.microservices.huertosdecine.entities.MovieEntity;
import java.util.List;
public class MovieService {
private final MovieDAO movieDAO;
public MovieService(Pool pool) {
this.movieDAO = new MovieDAO(pool);
}
public Future<List<MovieEntity>> getAll(QueryParams params) {
return movieDAO.getAll(params);
}
public Future<MovieEntity> getById(Integer id) {
return movieDAO.getById(id).compose(movie -> {
if (movie == null) {
return Future.failedFuture(new NotFoundException("Movie not found in the database"));
}
return Future.succeededFuture(movie);
});
}
public Future<MovieEntity> create(MovieEntity movie) {
return movieDAO.insert(movie);
}
public Future<MovieEntity> update(MovieEntity movie) {
return getById(movie.getMovie_id()).compose(existing -> {
if (existing == null) {
return Future.failedFuture(new NotFoundException("Movie not found in the database"));
}
return movieDAO.update(movie);
});
}
public Future<Boolean> delete(Integer id) {
return getById(id).compose(existing -> {
if (existing == null) {
return Future.failedFuture(new NotFoundException("Movie not found in the database"));
}
return movieDAO.delete(id);
});
}
}

View File

@@ -0,0 +1,137 @@
package net.miarma.api.microservices.huertosdecine.services;
import io.vertx.core.Future;
import io.vertx.core.json.JsonObject;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.exceptions.BadRequestException;
import net.miarma.api.backlib.exceptions.ForbiddenException;
import net.miarma.api.backlib.exceptions.NotFoundException;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.backlib.security.PasswordHasher;
import net.miarma.api.backlib.core.dao.UserDAO;
import net.miarma.api.backlib.core.entities.UserEntity;
import net.miarma.api.backlib.core.services.UserService;
import net.miarma.api.microservices.huertosdecine.dao.UserMetadataDAO;
import net.miarma.api.microservices.huertosdecine.dao.ViewerDAO;
import net.miarma.api.microservices.huertosdecine.entities.UserMetadataEntity;
import net.miarma.api.microservices.huertosdecine.entities.ViewerEntity;
import net.miarma.api.backlib.util.UserNameGenerator;
import java.security.NoSuchAlgorithmException;
import java.util.List;
public class ViewerService {
private final UserDAO userDAO;
private final UserMetadataDAO userMetadataDAO;
private final ViewerDAO viewerDAO;
private final UserService userService;
public ViewerService(Pool pool) {
this.userDAO = new UserDAO(pool);
this.userMetadataDAO = new UserMetadataDAO(pool);
this.viewerDAO = new ViewerDAO(pool);
this.userService = new UserService(pool);
}
public Future<JsonObject> login(String emailOrUsername, String password, boolean keepLoggedIn) {
return userService.login(emailOrUsername, password, keepLoggedIn).compose(json -> {
JsonObject loggedUserJson = json.getJsonObject("loggedUser");
UserEntity user = Constants.GSON.fromJson(loggedUserJson.encode(), UserEntity.class);
if (user == null) {
return Future.failedFuture(new BadRequestException("Invalid credentials"));
}
if (user.getGlobal_status() != Constants.CoreUserGlobalStatus.ACTIVE) {
return Future.failedFuture(new ForbiddenException("User is not active"));
}
return userMetadataDAO.getById(user.getUser_id()).compose(metadata -> {
if (metadata.getStatus() != Constants.CineUserStatus.ACTIVE) {
return Future.failedFuture(new ForbiddenException("User is not active"));
}
ViewerEntity viewer = new ViewerEntity(user, metadata);
return Future.succeededFuture(new JsonObject()
.put("token", json.getString("token"))
.put("loggedUser", new JsonObject(Constants.GSON.toJson(viewer)))
);
});
});
}
public Future<List<ViewerEntity>> getAll() {
return viewerDAO.getAll();
}
public Future<List<ViewerEntity>> getAll(QueryParams params) {
return viewerDAO.getAll(params);
}
public Future<ViewerEntity> getById(Integer id) {
return viewerDAO.getById(id).compose(viewer -> {
if (viewer == null) {
return Future.failedFuture(new NotFoundException("Viewer not found in the database"));
}
return Future.succeededFuture(viewer);
});
}
public Future<ViewerEntity> create(ViewerEntity viewer) {
viewer.setPassword(PasswordHasher.hash(viewer.getPassword()));
if (viewer.getEmail() == null || viewer.getEmail().isBlank()) viewer.setEmail(null);
String baseName = viewer.getDisplay_name().split(" ")[0].toLowerCase();
String userName;
try {
userName = UserNameGenerator.generateUserName(baseName, viewer.getDisplay_name(), 3);
viewer.setUser_name(userName);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return userDAO.insert(UserEntity.from(viewer)).compose(user -> {
UserMetadataEntity metadata = UserMetadataEntity.fromViewerEntity(viewer);
metadata.setUser_id(user.getUser_id());
return userMetadataDAO.upsert(metadata).compose(meta ->
userDAO.update(user).map(updatedUser -> new ViewerEntity(updatedUser, meta)));
});
}
public Future<UserMetadataEntity> createMetadata(UserMetadataEntity userMetadata) {
if (userMetadata.getUser_id() == null) {
return Future.failedFuture(new BadRequestException("User ID is required"));
}
return userMetadataDAO.upsert(userMetadata).compose(Future::succeededFuture);
}
public Future<ViewerEntity> update(ViewerEntity viewer) {
return getById(viewer.getUser_id()).compose(existing -> {
if (existing == null) {
return Future.failedFuture(new NotFoundException("Member in the database"));
}
if (viewer.getPassword() != null && !viewer.getPassword().isEmpty() &&
!viewer.getPassword().equals(existing.getPassword())) {
viewer.setPassword(PasswordHasher.hash(viewer.getPassword()));
} else {
viewer.setPassword(existing.getPassword());
}
return userDAO.update(UserEntity.from(viewer)).compose(updatedUser -> userMetadataDAO.update(UserMetadataEntity.fromViewerEntity(viewer)).map(updatedMeta -> new ViewerEntity(updatedUser, updatedMeta)));
});
}
public Future<ViewerEntity> delete(Integer id) {
return getById(id).compose(viewer ->
userDAO.delete(id).compose(deletedUser ->
userMetadataDAO.delete(viewer.getUser_id())
.map(deletedMetadata -> viewer)
)
);
}
}

View File

@@ -0,0 +1,57 @@
package net.miarma.api.microservices.huertosdecine.services;
import io.vertx.core.Future;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.exceptions.NotFoundException;
import net.miarma.api.backlib.http.QueryParams;
import net.miarma.api.backlib.security.JWTManager;
import net.miarma.api.microservices.huertosdecine.dao.VoteDAO;
import net.miarma.api.microservices.huertosdecine.entities.VoteEntity;
import java.util.List;
public class VoteService {
private final VoteDAO voteDAO;
public VoteService(Pool pool) {
this.voteDAO = new VoteDAO(pool);
}
public Future<List<VoteEntity>> getAll(QueryParams params) {
return voteDAO.getAll(params);
}
public Future<VoteEntity> getByUserId(Integer userId) {
return voteDAO.getById(userId);
}
public Future<List<VoteEntity>> getVotesByMovieId(Integer movieId) {
return voteDAO.getVotesByMovieId(movieId).compose(list -> {
if (list.isEmpty()) {
return Future.failedFuture(new NotFoundException("No votes found for the specified movie ID"));
}
return Future.succeededFuture(list);
});
}
public Future<VoteEntity> create(VoteEntity vote) {
return voteDAO.upsert(vote);
}
public Future<Boolean> delete(Integer userId) {
return getByUserId(userId).compose(existing -> {
if (existing == null) {
return Future.failedFuture(new NotFoundException("Vote not found in the database"));
}
Integer movieId = existing.getMovie_id();
return voteDAO.delete(movieId);
});
}
public Future<VoteEntity> getVoteSelf(String token) {
Integer userId = JWTManager.getInstance().getUserId(token);
return voteDAO.getById(userId);
}
}

View File

@@ -0,0 +1,119 @@
package net.miarma.api.microservices.huertosdecine.verticles;
import java.util.stream.Collectors;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.ConfigManager;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.db.DatabaseProvider;
import net.miarma.api.backlib.util.EventBusUtil;
import net.miarma.api.backlib.util.RouterUtil;
import net.miarma.api.microservices.huertosdecine.entities.VoteEntity;
import net.miarma.api.microservices.huertosdecine.routing.CineDataRouter;
import net.miarma.api.microservices.huertosdecine.services.ViewerService;
import net.miarma.api.microservices.huertosdecine.services.VoteService;
public class CineDataVerticle extends AbstractVerticle {
private ConfigManager configManager;
private VoteService voteService;
private ViewerService viewerService;
@Override
public void start(Promise<Void> startPromise) {
configManager = ConfigManager.getInstance();
Pool pool = DatabaseProvider.createPool(vertx, configManager);
voteService = new VoteService(pool);
viewerService = new ViewerService(pool);
Router router = Router.router(vertx);
RouterUtil.attachLogger(router);
CineDataRouter.mount(router, vertx, pool);
registerLogicVerticleConsumer();
vertx.createHttpServer()
.requestHandler(router)
.listen(configManager.getIntProperty("cine.data.port"), res -> {
if (res.succeeded()) startPromise.complete();
else startPromise.fail(res.cause());
});
}
private void registerLogicVerticleConsumer() {
vertx.eventBus().consumer(Constants.CINE_EVENT_BUS, message -> {
JsonObject body = (JsonObject) message.body();
String action = body.getString("action");
switch (action) {
case "login" -> {
String email = body.getString("email", null);
String userName = body.getString("userName", null);
String password = body.getString("password");
boolean keepLoggedIn = body.getBoolean("keepLoggedIn", false);
viewerService.login(email != null ? email : userName, password, keepLoggedIn)
.onSuccess(message::reply)
.onFailure(EventBusUtil.fail(message));
}
case "getVotesOnMovieByUserId" -> {
Integer movieId = body.getInteger("movie_id");
voteService.getVotesByMovieId(movieId)
.onSuccess(votes -> {
if (votes.isEmpty()) {
message.reply(new JsonObject().put("message", "No votes found for this movie and viewer"));
} else {
String votesJson = votes.stream()
.map(Constants.GSON::toJson)
.collect(Collectors.joining(",", "[", "]"));
message.reply(new JsonArray(votesJson));
}
})
.onFailure(EventBusUtil.fail(message));
}
case "getVotes" -> voteService.getVotesByMovieId(body.getInteger("movie_id"))
.onSuccess(votes -> {
String votesJson = votes.stream()
.map(Constants.GSON::toJson)
.collect(Collectors.joining(",", "[", "]"));
message.reply(new JsonArray(votesJson));
})
.onFailure(EventBusUtil.fail(message));
case "addVote" -> {
VoteEntity vote = Constants.GSON.fromJson(body.encode(), VoteEntity.class);
voteService.create(vote)
.onSuccess(createdVote -> message.reply(new JsonObject(Constants.GSON.toJson(createdVote))))
.onFailure(EventBusUtil.fail(message));
}
case "deleteVote" -> {
Integer userId = body.getInteger("user_id");
voteService.delete(userId)
.onSuccess(deletedVote -> message.reply(new JsonObject(Constants.GSON.toJson(deletedVote))))
.onFailure(EventBusUtil.fail(message));
}
case "getVoteSelf" -> {
String token = body.getString("token");
voteService.getVoteSelf(token)
.onSuccess(vote -> message.reply(new JsonObject(Constants.GSON.toJson(vote))))
.onFailure(EventBusUtil.fail(message));
}
default -> EventBusUtil.fail(message).handle(new IllegalArgumentException("Unknown action: " + action));
}
});
}
}

View File

@@ -0,0 +1,32 @@
package net.miarma.api.microservices.huertosdecine.verticles;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.handler.BodyHandler;
import io.vertx.sqlclient.Pool;
import net.miarma.api.backlib.ConfigManager;
import net.miarma.api.backlib.db.DatabaseProvider;
import net.miarma.api.backlib.util.RouterUtil;
import net.miarma.api.microservices.huertosdecine.routing.CineLogicRouter;
public class CineLogicVerticle extends AbstractVerticle {
private ConfigManager configManager;
@Override
public void start(Promise<Void> startPromise) {
configManager = ConfigManager.getInstance();
Pool pool = DatabaseProvider.createPool(vertx, configManager);
Router router = Router.router(vertx);
RouterUtil.attachLogger(router);
CineLogicRouter.mount(router, vertx, pool);
vertx.createHttpServer()
.requestHandler(router)
.listen(configManager.getIntProperty("cine.logic.port"), res -> {
if (res.succeeded()) startPromise.complete();
else startPromise.fail(res.cause());
});
}
}

View File

@@ -0,0 +1,56 @@
package net.miarma.api.microservices.huertosdecine.verticles;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Promise;
import net.miarma.api.backlib.ConfigManager;
import net.miarma.api.backlib.Constants;
import net.miarma.api.backlib.LogAccumulator;
import net.miarma.api.backlib.util.DeploymentUtil;
public class CineMainVerticle extends AbstractVerticle {
private ConfigManager configManager;
@Override
public void start(Promise<Void> startPromise) {
try {
this.configManager = ConfigManager.getInstance();
deployVerticles();
startPromise.complete();
} catch (Exception e) {
Constants.LOGGER.error(DeploymentUtil.failMessage(CineMainVerticle.class, e));
startPromise.fail(e);
}
}
private void deployVerticles() {
vertx.deployVerticle(new CineDataVerticle(), result -> {
if (result.succeeded()) {
String message = String.join("\n\r ",
DeploymentUtil.successMessage(CineDataVerticle.class),
DeploymentUtil.apiUrlMessage(
configManager.getHost(),
configManager.getIntProperty("cine.data.port")
)
);
LogAccumulator.add(message);
} else {
LogAccumulator.add(DeploymentUtil.failMessage(CineDataVerticle.class, result.cause()));
}
});
vertx.deployVerticle(new CineLogicVerticle(), result -> {
if (result.succeeded()) {
String message = String.join("\n\r ",
DeploymentUtil.successMessage(CineLogicVerticle.class),
DeploymentUtil.apiUrlMessage(
configManager.getHost(),
configManager.getIntProperty("cine.logic.port")
)
);
LogAccumulator.add(message);
} else {
LogAccumulator.add(DeploymentUtil.failMessage(CineLogicVerticle.class, result.cause()));
}
});
}
}