api, games page update, scripts

This commit is contained in:
Michael Wain 2024-02-18 03:19:13 +03:00
parent 5d81f6b890
commit bafd220a4c
41 changed files with 1561 additions and 24 deletions

View File

@ -0,0 +1,20 @@
package com.alterdekim.game.component;
import com.alterdekim.game.service.UserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class OnlineStatus {
@Autowired
private UserServiceImpl userService;
@Scheduled(fixedRate = 50000)
private void resetOnlineStatus() {
userService.setAllOffline();
}
}

View File

@ -0,0 +1,165 @@
package com.alterdekim.game.controller;
import com.alterdekim.game.dto.*;
import com.alterdekim.game.entities.Chat;
import com.alterdekim.game.entities.User;
import com.alterdekim.game.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.async.DeferredResult;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Controller
public class APIController {
@Autowired
private RoomServiceImpl roomService;
@Autowired
private RoomPlayerServiceImpl roomPlayerService;
@Autowired
private ChatServiceImpl chatService;
@Autowired
private BannerServiceImpl bannerService;
@Autowired
private TextDataValServiceImpl textDataValService;
@Autowired
private UserServiceImpl userService;
@GetMapping("/api/v1/games/list")
public ResponseEntity<List<RoomResult>> gamesList() {
List<RoomResult> results = roomService.getAll()
.stream()
.map(room -> new RoomResult(room, roomPlayerService.findByRoomId(room.getId())))
.collect(Collectors.toList());
return ResponseEntity.ok(results);
}
@GetMapping("/api/v1/chat/history/{count}/")
public ResponseEntity<ChatResult> chatList(@PathVariable Integer count ) {
List<Chat> results = chatService.getLastChats(count);
results = results.stream().map( c -> {
String message = c.getMessage();
for( int i = 0; i < message.length(); i++ ) {
if( message.charAt(i) == '@' ) {
int u = message.substring(i).indexOf(' ') + i;
String username = message.substring(i+1, u);
User user = userService.findByUsername(username);
if( user != null ) {
Long uid = user.getId();
message = message.substring(0, i) + "<a href=\"/profile/" + uid + "\" class=\"chat-history-user\"><span class=\"_nick\">" + username + "</span></a>" + message.substring(u + 1);
} else {
message = message.substring(0, i) + username + message.substring(u + 1);
}
i = 0;
}
}
c.setMessage(message);
return c;
}).collect(Collectors.toList());
List<UserResult> users = results.stream()
.map(Chat::getUserId)
.distinct()
.map( l -> userService.findById(l) )
.map( u -> new UserResult(u.getId(), u.getUsername()) )
.collect(Collectors.toList());
return ResponseEntity.ok(new ChatResult(results, users));
}
@GetMapping("/api/v1/market/banners/{lang}/")
public ResponseEntity<List<Banner>> getBanners( @PathVariable String lang ) {
List<Banner> banners = null;
if( lang.equals("ru") ) {
banners = bannerService.getAllActive()
.stream()
.map( b -> new Banner(b.getId(),
textDataValService.findById(b.getTitleId()).getTextRus(),
textDataValService.findById(b.getDescriptionId()).getTextRus(),
b.getGradientInfo(),
b.getImageUrl()))
.collect(Collectors.toList());
} else {
banners = bannerService.getAllActive()
.stream()
.map( b -> new Banner(b.getId(),
textDataValService.findById(b.getTitleId()).getTextEng(),
textDataValService.findById(b.getDescriptionId()).getTextEng(),
b.getGradientInfo(),
b.getImageUrl()))
.collect(Collectors.toList());
}
return ResponseEntity.ok(banners);
}
@PostMapping("/api/v1/chat/send")
public ResponseEntity<String> sendChat( @RequestBody String message ) {
try {
message = URLDecoder.decode(message, "UTF-8");
message = message.substring(0, message.length() - 1);
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Long userId = userService.findByUsername(((org.springframework.security.core.userdetails.User) auth.getPrincipal()).getUsername()).getId();
chatService.sendChat(new Chat(userId, message, System.currentTimeMillis() / 1000L));
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
}
return ResponseEntity.accepted().build();
}
@GetMapping("/api/v1/notify/get/{last_chat_id}/")
public ResponseEntity<LongPollResult> getNotify(@PathVariable Long last_chat_id ) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Long userId = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername()).getId();
userService.updateOnline(userId);
Integer onlineCount = userService.countByIsOnline();
List<Chat> results = chatService.getAfterLastChatId(last_chat_id);
List<UserResult> users = results.stream()
.map(Chat::getUserId)
.distinct()
.map( l -> userService.findById(l) )
.map( u -> new UserResult(u.getId(), u.getUsername()) )
.collect(Collectors.toList());
results = results.stream().map( c -> {
String message = c.getMessage();
for( int i = 0; i < message.length(); i++ ) {
if( message.charAt(i) == '@' ) {
int u = message.substring(i).indexOf(' ') + i;
String username = message.substring(i+1, u);
User user = userService.findByUsername(username);
if( user != null ) {
Long uid = user.getId();
message = message.substring(0, i) + "<a href=\"/profile/" + uid + "\" class=\"chat-history-user\"><span class=\"_nick\">" + username + "</span></a>" + message.substring(u + 1);
} else {
message = message.substring(0, i) + username + message.substring(u + 1);
}
i = 0;
}
}
c.setMessage(message);
return c;
}).collect(Collectors.toList());
return ResponseEntity.ok(new LongPollResult(onlineCount, results, users));
}
}

View File

@ -0,0 +1,24 @@
package com.alterdekim.game.dto;
import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class Banner {
private Long id;
private String title;
private String description;
private String gradientInfo;
private String imageUrl;
}

View File

@ -0,0 +1,16 @@
package com.alterdekim.game.dto;
import com.alterdekim.game.entities.Chat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class ChatResult {
private List<Chat> messages;
private List<UserResult> users;
}

View File

@ -0,0 +1,17 @@
package com.alterdekim.game.dto;
import com.alterdekim.game.entities.Chat;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class LongPollResult {
private Integer onlineCount;
private List<Chat> messages;
private List<UserResult> users;
}

View File

@ -0,0 +1,17 @@
package com.alterdekim.game.dto;
import com.alterdekim.game.entities.Room;
import com.alterdekim.game.entities.RoomPlayer;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class RoomResult {
private Room room;
private List<RoomPlayer> players;
}

View File

@ -0,0 +1,13 @@
package com.alterdekim.game.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class UserResult {
private Long id;
private String username;
}

View File

@ -0,0 +1,37 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "chat_message")
public class Chat {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long userId;
@Column(length = 955)
@NotNull
private String message;
@Column(nullable = false)
private Long createdAt;
public Chat(Long userId, String message, Long createdAt) {
this.userId = userId;
this.message = message;
this.createdAt = createdAt;
}
}

View File

@ -0,0 +1,35 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "friend_status")
public class FriendStatus {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long firstUserId;
@Column(nullable = false)
private Long secondUserId;
@Column(nullable = false)
private Integer status;
public FriendStatus(Long firstUserId, Long secondUserId, Integer status) {
this.firstUserId = firstUserId;
this.secondUserId = secondUserId;
this.status = status;
}
}

View File

@ -0,0 +1,43 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "market_banner")
public class MarketBanner {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Boolean isActive;
@Column(nullable = false)
private Long titleId;
@Column(nullable = false)
private Long descriptionId;
@Column(nullable = false)
private String gradientInfo;
@Column(nullable = false)
private String imageUrl;
public MarketBanner(Boolean isActive, Long titleId, Long descriptionId, String gradientInfo, String imageUrl) {
this.isActive = isActive;
this.titleId = titleId;
this.descriptionId = descriptionId;
this.gradientInfo = gradientInfo;
this.imageUrl = imageUrl;
}
}

View File

@ -0,0 +1,42 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mission")
public class Mission {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long nameId;
@Column(nullable = false)
private Integer xp;
@Column(nullable = false)
private Integer count;
@Column(nullable = false)
private Long timestamp;
@Column(nullable = false)
private Boolean isActive;
public Mission(Long nameId, Integer xp, Integer count, Long timestamp, Boolean isActive) {
this.nameId = nameId;
this.xp = xp;
this.count = count;
this.timestamp = timestamp;
this.isActive = isActive;
}
}

View File

@ -0,0 +1,30 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "mission_progress")
public class MissionProgress {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long missionId;
@Column(nullable = false)
private Long userId;
public MissionProgress(Long missionId, Long userId) {
this.missionId = missionId;
this.userId = userId;
}
}

View File

@ -0,0 +1,34 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "room")
public class Room {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Integer playerCount;
@Column(nullable = false)
private Boolean isPrivate;
@Column(nullable = false)
private String password;
public Room(Integer playerCount, Boolean isPrivate, String password) {
this.playerCount = playerCount;
this.isPrivate = isPrivate;
this.password = password;
}
}

View File

@ -0,0 +1,30 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "room_player")
public class RoomPlayer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private Long roomId;
@Column(nullable = false)
private Long userId;
public RoomPlayer(Long roomId, Long userId) {
this.roomId = roomId;
this.userId = userId;
}
}

View File

@ -0,0 +1,33 @@
package com.alterdekim.game.entities;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "textdata_val")
public class TextDataVal {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 65555)
@NotNull
private String textEng;
@Column(length = 65555)
@NotNull
private String textRus;
public TextDataVal(String textEng, String textRus) {
this.textEng = textEng;
this.textRus = textRus;
}
}

View File

@ -28,6 +28,9 @@ public class User {
@Column(nullable=false) @Column(nullable=false)
private String password; private String password;
@Column(columnDefinition = "boolean default false")
private Boolean isOnline;
@ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL) @ManyToMany(fetch = FetchType.EAGER, cascade=CascadeType.ALL)
@JoinTable( @JoinTable(
name="users_roles", name="users_roles",

View File

@ -0,0 +1,20 @@
package com.alterdekim.game.repository;
import com.alterdekim.game.entities.Chat;
import com.alterdekim.game.entities.Room;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ChatRepository extends JpaRepository<Chat, Long> {
@Query(value = "SELECT c FROM Chat c ORDER BY c.createdAt DESC LIMIT :count")
List<Chat> getLastChats(@Param(value = "count") Integer count);
@Query(value = "SELECT c FROM Chat c WHERE c.id > :lastChatId ORDER BY c.createdAt ASC")
List<Chat> getAfterLastChatId(@Param(value = "lastChatId") Long lastChatId);
}

View File

@ -0,0 +1,14 @@
package com.alterdekim.game.repository;
import com.alterdekim.game.entities.Chat;
import com.alterdekim.game.entities.MarketBanner;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
public interface MarketBannerRepository extends JpaRepository<MarketBanner, Long> {
@Query(value = "SELECT m FROM MarketBanner m WHERE m.isActive = true")
List<MarketBanner> getAllActive();
}

View File

@ -0,0 +1,13 @@
package com.alterdekim.game.repository;
import com.alterdekim.game.entities.Room;
import com.alterdekim.game.entities.RoomPlayer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface RoomPlayerRepository extends JpaRepository<RoomPlayer, Long> {
List<RoomPlayer> findByRoomId(Long roomId);
}

View File

@ -0,0 +1,10 @@
package com.alterdekim.game.repository;
import com.alterdekim.game.entities.Room;
import com.alterdekim.game.entities.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface RoomRepository extends JpaRepository<Room, Long> {
}

View File

@ -0,0 +1,13 @@
package com.alterdekim.game.repository;
import com.alterdekim.game.entities.Room;
import com.alterdekim.game.entities.TextDataVal;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface TextDataValRepository extends JpaRepository<TextDataVal, Long> {
Optional<TextDataVal> findById(Long id);
}

View File

@ -2,9 +2,25 @@ package com.alterdekim.game.repository;
import com.alterdekim.game.entities.User; import com.alterdekim.game.entities.User;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository @Repository
public interface UserRepository extends JpaRepository<User, Integer> { public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username); User findByUsername(String username);
@Transactional
@Modifying
@Query(value = "UPDATE User u SET u.isOnline = true WHERE u.id = :uuid")
void setOnline(@Param(value = "uuid") Long id);
@Transactional
@Modifying
@Query(value = "UPDATE User u SET u.isOnline = false")
void setAllOffline();
Integer countByIsOnline(boolean isOnline);
} }

View File

@ -7,11 +7,13 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.firewall.StrictHttpFirewall;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@ -31,6 +33,8 @@ public class SpringSecurity {
authorize authorize
.requestMatchers("/game").hasAnyAuthority("ROLE_ADMIN") .requestMatchers("/game").hasAnyAuthority("ROLE_ADMIN")
.requestMatchers("/games").hasAnyAuthority("ROLE_ADMIN") .requestMatchers("/games").hasAnyAuthority("ROLE_ADMIN")
.requestMatchers("/profile/**").hasAnyAuthority("ROLE_ADMIN")
.requestMatchers("/api/**").hasAnyAuthority("ROLE_ADMIN")
.requestMatchers("/static/**").permitAll() .requestMatchers("/static/**").permitAll()
.requestMatchers("/access-denied").permitAll() .requestMatchers("/access-denied").permitAll()
.requestMatchers("/signup").permitAll() .requestMatchers("/signup").permitAll()
@ -75,5 +79,12 @@ public class SpringSecurity {
public static PasswordEncoder passwordEncoder(){ public static PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(); return new BCryptPasswordEncoder();
} }
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowSemicolon(true);
return (web) -> web.httpFirewall(firewall);
}
} }

View File

@ -0,0 +1,9 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.MarketBanner;
import java.util.List;
public interface BannerService {
List<MarketBanner> getAllActive();
}

View File

@ -0,0 +1,22 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.MarketBanner;
import com.alterdekim.game.repository.MarketBannerRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BannerServiceImpl implements BannerService {
private final MarketBannerRepository repository;
public BannerServiceImpl(MarketBannerRepository repository) {
this.repository = repository;
}
@Override
public List<MarketBanner> getAllActive() {
return repository.getAllActive();
}
}

View File

@ -0,0 +1,13 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.Chat;
import java.util.List;
public interface ChatService {
List<Chat> getLastChats(Integer count);
void sendChat(Chat chat);
List<Chat> getAfterLastChatId(Long lastChatId);
}

View File

@ -0,0 +1,32 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.Chat;
import com.alterdekim.game.repository.ChatRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ChatServiceImpl implements ChatService {
private final ChatRepository chatRepository;
public ChatServiceImpl(ChatRepository chatRepository) {
this.chatRepository = chatRepository;
}
@Override
public List<Chat> getLastChats(Integer count) {
return chatRepository.getLastChats(count);
}
@Override
public void sendChat(Chat chat) {
chatRepository.save(chat);
}
@Override
public List<Chat> getAfterLastChatId(Long lastChatId) {
return chatRepository.getAfterLastChatId(lastChatId);
}
}

View File

@ -0,0 +1,12 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.Room;
import com.alterdekim.game.entities.RoomPlayer;
import java.util.List;
public interface RoomPlayerService {
List<RoomPlayer> getAll();
List<RoomPlayer> findByRoomId(Long roomId);
}

View File

@ -0,0 +1,27 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.RoomPlayer;
import com.alterdekim.game.repository.RoomPlayerRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RoomPlayerServiceImpl implements RoomPlayerService{
private final RoomPlayerRepository repository;
public RoomPlayerServiceImpl(RoomPlayerRepository repository) {
this.repository = repository;
}
@Override
public List<RoomPlayer> getAll() {
return repository.findAll();
}
@Override
public List<RoomPlayer> findByRoomId(Long roomId) {
return repository.findByRoomId(roomId);
}
}

View File

@ -0,0 +1,9 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.Room;
import java.util.List;
public interface RoomService {
List<Room> getAll();
}

View File

@ -0,0 +1,21 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.Room;
import com.alterdekim.game.repository.RoomRepository;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class RoomServiceImpl implements RoomService {
private final RoomRepository roomRepository;
public RoomServiceImpl(RoomRepository roomRepository) {
this.roomRepository = roomRepository;
}
@Override
public List<Room> getAll() {
return roomRepository.findAll();
}
}

View File

@ -0,0 +1,7 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.TextDataVal;
public interface TextDataValService {
TextDataVal findById(Long id);
}

View File

@ -0,0 +1,20 @@
package com.alterdekim.game.service;
import com.alterdekim.game.entities.TextDataVal;
import com.alterdekim.game.repository.TextDataValRepository;
import org.springframework.stereotype.Service;
@Service
public class TextDataValServiceImpl implements TextDataValService {
private final TextDataValRepository textDataValRepository;
public TextDataValServiceImpl(TextDataValRepository textDataValRepository) {
this.textDataValRepository = textDataValRepository;
}
@Override
public TextDataVal findById(Long id) {
return textDataValRepository.findById(id).orElse(null);
}
}

View File

@ -11,5 +11,7 @@ public interface UserService {
User findByUsername(String usernane); User findByUsername(String usernane);
List<UserDTO> findAllUsers(); List<UserDTO> findAllUsers();
User findById(Long id);
} }

View File

@ -53,6 +53,11 @@ public class UserServiceImpl implements UserService {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
private UserDTO convertEntityToDto(User user){ private UserDTO convertEntityToDto(User user){
UserDTO userDto = new UserDTO(); UserDTO userDto = new UserDTO();
userDto.setUsername(user.getUsername()); userDto.setUsername(user.getUsername());
@ -64,5 +69,17 @@ public class UserServiceImpl implements UserService {
role.setName("ROLE_ADMIN"); role.setName("ROLE_ADMIN");
return roleRepository.save(role); return roleRepository.save(role);
} }
public void updateOnline(Long userId) {
userRepository.setOnline(userId);
}
public void setAllOffline() {
userRepository.setAllOffline();
}
public Integer countByIsOnline() {
return userRepository.countByIsOnline(true);
}
} }

View File

@ -32,6 +32,14 @@ footer {
background-color: #37bc9d; background-color: #37bc9d;
color: #fff; color: #fff;
border-color: #37bc9d; border-color: #37bc9d;
--bs-btn-active-bg: #37bc9d;
}
.btn-primary:active {
background-color: #37bc9d;
color: #fff;
border-color: #37bc9d;
--bs-btn-active-bg: #37bc9d;
} }
.btn-primary:hover { .btn-primary:hover {
@ -49,4 +57,10 @@ footer {
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 0.2em; gap: 0.2em;
}
.navbar-profile-img {
width: 2.3rem;
height: 2.3rem;
border-radius: 50%;
} }

View File

@ -0,0 +1,142 @@
$.fn.pressEnter = function(fn) {
return this.each(function() {
$(this).bind('enterPress', fn);
$(this).keyup(function(e){
if(e.keyCode == 13)
{
$(this).trigger("enterPress");
}
})
});
};
var last_chat_id = 0;
function findUser(users, id) {
for( let i = 0; i < users.length; i++ ) {
if( users[i].id == id ) {
return users[i];
}
}
}
function parseTime(unix_timestamp) {
var date = new Date(unix_timestamp * 1000);
var hours = date.getHours();
var minutes = "0" + date.getMinutes();
return hours + ':' + minutes.substr(-2);
}
function replyButtonClicked(obj) {
let userid = $(obj).attr('data-userid');
let username = $(obj).attr('data-username');
$('#chat-message-input').val($('#chat-message-input').val() + " @" + username + "");
}
setInterval(function() {
$.ajax({
url: "/api/v1/notify/get/" + last_chat_id + "/",
method: "GET"
}).done(function(data) {
console.log(data);
let onlineCount = data.onlineCount;
$(".chat-title").find("span").html(onlineCount + " online");
let messages = data.messages;
let users = data.users;
if( messages.length > 0 ) {
last_chat_id = messages[0].id;
}
for( let i = 0; i < messages.length; i++ ) {
let obj = messages[i];
let time = parseTime(obj.createdAt);
let username = findUser(users, obj.userId).username;
let userid = obj.userId;
let msgtext = obj.message;
let html = '<div class="chat-history-one"><div class="chat-history-info"><span class="time">'+time+'</span><ion-icon name="arrow-undo-outline" class="reply-button" data-userid="'+userid+'" data-username="'+username+'" onClick="replyButtonClicked(this)"></ion-icon></div><span><span class="chat-history-text chat-history-content-message"><span class="formatter"><a href="/profile/'+userid+'" class="chat-history-user"><span class="_nick">'+username+'</span></a><ion-icon name="remove-outline"></ion-icon><span>'+msgtext+'</span></span></span></span></div>';
$(".chat-history").append(html);
}
$("#chat_list").find(".chat-history").css("display", "");
$("#chat_list").find(".message-input").css("display", "");
$("#chat_list").find(".block-content").css("display", "none");
});
}, 5000);
$(document).ready(function() {
$("#players-count-range").on("input", function() {
$("label[for='players-count-range']").find("span").text($(this).val());
});
$('#chat-message-input').pressEnter(function() {
let txt = $(this).val();
$(this).val("");
if( txt != "" ) {
$.ajax({
url: "/api/v1/chat/send",
method: "POST",
data: txt
});
}
});
$.ajax({
url: "/api/v1/games/list",
method: "GET"
}).done(function(data) {
console.log(data);
});
// block-content
$.ajax({
url: "/api/v1/chat/history/100/",
method: "GET"
}).done(function(data) {
console.log(data);
let messages = data.messages;
let users = data.users;
if( messages.length > 0 ) {
last_chat_id = messages[0].id;
}
for( let i = messages.length-1; i >= 0; i-- ) {
let obj = messages[i];
let time = parseTime(obj.createdAt);
let username = findUser(users, obj.userId).username;
let userid = obj.userId;
let msgtext = obj.message;
let html = '<div class="chat-history-one"><div class="chat-history-info"><span class="time">'+time+'</span><ion-icon name="arrow-undo-outline" class="reply-button" data-userid="'+userid+'" data-username="'+username+'" onClick="replyButtonClicked(this)"></ion-icon></div><span><span class="chat-history-text chat-history-content-message"><span class="formatter"><a href="/profile/'+userid+'" class="chat-history-user"><span class="_nick">'+username+'</span></a><ion-icon name="remove-outline"></ion-icon><span>'+msgtext+'</span></span></span></span></div>';
$(".chat-history").append(html);
}
$("#chat_list").find(".chat-history").css("display", "");
$("#chat_list").find(".message-input").css("display", "");
$("#chat_list").find(".block-content").css("display", "none");
});
$.ajax({
url: "/api/v1/market/banners/en/",
method: "GET"
}).done(function(data) {
console.log(data);
for( var i = 0; i < data.length; i++ ) {
let obj = data[i];
let tag = '';
if( i != 0 ) {
let html = '<button type="button" data-bs-target="#market-carousel" data-bs-slide-to="'+i+'" aria-label="Slide '+(i+1)+'"></button>';
$("#market-carousel").find(".carousel-indicators").append(html);
} else {
tag = 'active';
}
let _ihtml = '<div class="carousel-item '+tag+'"><div class="carousel-item-background w-100 rounded" style="background: '+obj.gradientInfo+'; min-height: 160px"><div class="carousel-item-body"><div class="carousel-title-text">'+obj.title+'</div><div class="carousel-body-text">'+obj.description+'</div></div></div></div>';
$("#market-carousel").find(".carousel-inner").append(_ihtml);
}
$(".market").find(".spinner-grow").css("display", "none");
$(".market").find("#market-carousel").css("display", "");
});
/*$.ajax({
url: "/api/v1/games/list",
method: "GET"
}).done(function(data) {
console.log(data);
});*/
});

View File

@ -0,0 +1,11 @@
function resizeTable() {
var $window = $(window);
var height = window.innerHeight;
var theight = $('.game').height();
var scale = height / theight;
$('.game').css('transform', 'scale(' + scale + ')');
}
resizeTable();
$(window).resize(function(evt) {
resizeTable();
});

View File

@ -2,7 +2,8 @@
<nav class="navbar navbar-expand-lg navbar-light"> <nav class="navbar navbar-expand-lg navbar-light">
<div class="container-fluid"> <div class="container-fluid">
<div class="collapse navbar-collapse justify-content-center" id="navbarNav"> <div class="collapse navbar-collapse justify-content-center" id="navbarNav">
<a class="navbar-brand navbar-brand-custom" href="/">Nosedive</a> <a class="navbar-brand navbar-brand-custom navbar-brand-custom-plain" style="display: none" href="/">Nosedive</a>
<a class="navbar-brand navbar-brand-custom navbar-brand-custom-gradient" href="/" style="font-weight: 600; background: linear-gradient(90deg, hsl(166, 55%, 30%) 0%, rgba(55,188,157,1) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">Nosedive</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
@ -26,6 +27,11 @@
<span>Inventory</span> <span>Inventory</span>
</a> </a>
</li> </li>
<li class="nav-item">
<a href="/profile/" class="navbar-btn">
<img class="navbar-profile-img" src="https://avatars.githubusercontent.com/u/102559365?v=4"/>
</a>
</li>
</ul> </ul>
</th:block> </th:block>
<th:block sec:authorize="isAnonymous()"> <th:block sec:authorize="isAnonymous()">

View File

@ -62,42 +62,490 @@
.text-glowing { .text-glowing {
color: rgba(55, 188, 157, 1) !important; color: rgba(55, 188, 157, 1) !important;
} }
.mission-one {
margin-top: 10px;
border-top: 1px solid #e9eaec;
padding: 10px;
}
.mission-target>span {
font-weight: 700;
}
.mission-block>span {
font-weight: 700;
}
.progress {
margin-top: 5px;
height: 7px;
}
.progress-bar {
background-color: rgba(55, 188, 157, 1) !important;
}
.mission-block, .mission-target {
font-size: 13px;
margin-top: 5px;
display: flex;
align-items: center;
gap: 0.3em;
}
.mission-text {
font-size: 13px;
}
.friend-search {
margin: 20px;
line-height: 1.6;
}
.empty-list-message {
text-align: center;
margin: 20px;
}
.empty-list-message>p {
font-size: 13px;
}
.title > span {
color: #a7adb5;
font-size: 14px;
}
.chat-history {
padding: 20px;
margin-bottom: 15px;
width: 100%;
height: 280px;
overflow-x: hidden;
overflow-y: scroll;
word-wrap: break-word;
}
#market-carousel {
width: 100%;
}
.carousel-title-text {
font-size: 19px;
font-weight: 700;
color: #fff;
}
.carousel-body-text {
margin-top: 10px;
font-size: 14px;
line-height: 20px;
color: #fff;
}
.carousel-item-body {
padding: 0 70px;
}
.carousel-item-background {
display: flex;
flex-direction: column;
justify-content: center;
}
.chat-history-one {
margin: 5px 0;
}
.chat-history-info {
display: inline-flex;
align-items: center;
margin-right: 5px;
color: #989aa4;
transform: translateY(1px);
}
.chat-history-user {
padding: 0 6px;
text-decoration: none;
background-color: #b9bac1;
border-radius: 5px;
}
.chat-history-user>._nick {
color: #fff;
font-weight: 600;
}
.chat-history-text {
margin-left: 5px;
}
.chat-history-one>* {
font-size: 14px;
vertical-align: middle;
line-height: 21px;
}
.chat-history-info>.time {
margin-right: 5px;
}
.message-input {
margin: 20px;
line-height: 1.6;
}
.games-room-one {
display: flex;
flex-flow: column nowrap;
position: relative;
border-top: 1px solid;
border-color: #e6e6e6;
}
.games-room-one-body {
padding: 10px 20px;
}
.games-room-one-body-head {
display: flex;
flex-flow: row nowrap;
height: 25px;
}
.games-room-one-body-head-info {
flex-grow: 999;
display: flex;
flex-flow: row nowrap;
gap: 10px;
}
.games-room-one-body-members {
display: flex;
flex-flow: row nowrap;
margin-top: 13px;
margin-bottom: 5px;
justify-content: center;
}
.games-room-one-body-members-one {
position: relative;
margin: 0 5px;
width: calc(20% - 2 * 5px);
}
.games-room-one-body-members-one-nick {
margin-top: 5px;
height: 21px;
text-align: center;
line-height: 21px;
white-space: nowrap;
}
.games-room-one-body-members-one-nick > a {
color: #656d78;
font-size: 14px;
}
.games-room-one-body-members-one-nick > span {
color: #656d78;
font-size: 14px;
text-decoration: none;
}
.games-room-one-body-members-one-avatar {
display: flex;
justify-content: center;
align-items: center;
position: relative;
margin: auto;
border-radius: 100%;
width: 75px;
height: 75px;
background: center/cover no-repeat;
font: 50px Ionicons;
}
.games-room-one-body-head-info > ._type > div {
font-size: 15px;
}
.games-room-one-body-head-info > ._with_wormhole > div {
font-size: 15px;
}
._slot_join {
cursor: pointer;
}
#waiting_list > .title {
align-items: center;
display: flex;
position: relative;
}
#waiting_list > .title > a {
position: absolute;
right: 0;
}
body.modal-open > :not(.modal) {
-webkit-filter: blur(3px);
-moz-filter: blur(3px);
-o-filter: blur(3px);
-ms-filter: blur(3px);
filter: blur(3px);
}
.game-creation-modal-modes {
background-color: #f7f7f7;
flex-shrink: 0;
border-radius: 5px 0 0 5px;
padding: 10px 15px 10px 10px;
width: 250px;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.game-creation-modal-block {
flex-shrink: 0;
position: relative;
left: -5px;
border-radius: 5px;
padding: 20px 0;
width: 375px;
background-color: #fff;
box-shadow: 0 0 25px rgba(0,0,0,.1);
}
.game-creation-modal-body {
display: flex;
position: relative;
box-shadow: 0 0 100px rgba(0,0,0,.333);
border-radius: 5px;
width: 620px;
text-align: left;
}
.game-creation-modal-modes-one._regular._selected {
background: #8cc152;
}
.game-creation-modal-modes-one._selected {
color: #fff;
}
.game-creation-modal-modes-one {
border-radius: 5px;
padding: 10px 15px;
cursor: pointer;
}
.game-creation-modal-modes-one-title {
font-weight: 600;
font-size: 18px;
line-height: 21px;
}
.game-creation-modal-modes-one-subtitle {
margin-top: 4px;
font-size: 12px;
line-height: 15px;
opacity: .85;
}
.game-creation-modal-block-title {
margin-bottom: 10px;
font-weight: 600;
margin-top: 0;
font-size: 18px;
position: relative;
margin-left: 20px;
margin-right: 20px;
}
.game-creation-modal-block-subtitle {
margin-right: 20px;
margin-left: 20px;
margin-top: 10px;
margin-bottom: 10px;
font-size: 16px;
position: relative;
font-weight: 400;
}
.form-switch-game {
transform: scale(1.2);
margin-left: 3.5rem;
}
.form-check-input:checked {
background-color: #37bc9d;
border-color: #37bc9d;
}
#players-count-range, .players-range-value {
margin-left: 20px;
width: 80%;
}
.form-range::-webkit-slider-thumb {
background-color: #37bc9d;
}
.reply-button {
cursor: pointer;
}
</style> </style>
</head> </head>
<body> <body>
<th:block th:insert="~{fragments/navbar}"></th:block> <th:block th:insert="~{fragments/navbar}"></th:block>
<div class="container"> <div class="modal fade" id="game-creation-menu-modal" tabindex="-1" aria-labelledby="game-creation-menu-modal-title" style="display: none;" aria-hidden="true">
<div class="grid mt-5"> <div class="modal-dialog modal-dialog-centered">
<div class="g-col-4"> <div class="modal-content">
<div class="block"> <div class="game-creation-modal-body">
<div class="title">Achievements</div> <div class="game-creation-modal-modes">
<div class="block-content"> <div class="game-creation-modal-modes-one _regular _selected">
<div class="spinner-grow text-glowing" role="status"> <div class="game-creation-modal-modes-one-title">Regular game</div>
<span class="visually-hidden">Loading...</span> <div class="game-creation-modal-modes-one-subtitle">Classic Nosedive game.</div>
</div> </div>
</div> </div>
</div> <div class="game-creation-modal-block">
<div class="game-creation-modal-block-title">Regular game</div>
<div class="block" style="margin-top: 15px;"> <label for="players-count-range" class="form-label players-range-value">Players <span></span></label>
<div class="title">Friends</div> <input type="range" class="form-range" min="2" max="5" step="1" id="players-count-range">
<div class="block-content"> <div class="game-creation-modal-block-subtitle">Room settings</div>
<div class="spinner-grow text-glowing" role="status"> <div class="form-check form-switch form-switch-game">
<span class="visually-hidden">Loading...</span> <input class="form-check-input" type="checkbox" role="switch" id="flexSwitchCheckDefault">
<label class="form-check-label" for="flexSwitchCheckDefault">Private room</label>
</div>
<div style="display: flex; justify-content: center;">
<button class="btn btn-primary navbar-btn">
<span>Start</span>
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="g-col-8"> </div>
<div class="block transparent-override"> </div>
<div class="market"> <div class="container">
<div class="grid mt-5">
<div class="g-col-4">
<div class="block" id="missions_list">
<div class="title">Missions</div>
<div class="block-content">
<div class="spinner-grow text-glowing" role="status"> <div class="spinner-grow text-glowing" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
</div> </div>
</div> </div>
<!--<div>
<div class="mission-one">
<div class="mission-text">Pay on cell "tax"</div>
<div class="mission-target"><span>0</span>/<span>4</span></div>
<div class="progress" role="progressbar" aria-label="Example with label" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar" style="width: 25%"></div>
</div>
<div class="mission-block">
<ion-icon name="checkmark-circle-outline" role="img" class="md hydrated"></ion-icon>
<span>80</span>
XP
<ion-icon name="timer-outline" role="img" class="md hydrated"></ion-icon>
3 days
</div>
</div>
</div>-->
</div> </div>
<div class="block" style="margin-top: 15px;"> <div class="block" id="top_of_week" style="margin-top: 15px;">
<div class="title">Chat</div> <div class="title">Top of week</div>
<div class="block-content">
<div class="spinner-grow text-glowing" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<!--
<div>
<div class="empty-list-message">
<p>You are not in the top players of the week - win a competitive match first.</p>
</div>
</div>-->
</div>
<div class="block" id="friends_list" style="margin-top: 15px;">
<div class="title">Friends online</div>
<div class="block-content">
<div class="spinner-grow text-glowing" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
<!--<div>
<div class="friend-search">
<input type="text" class="friend-search-input form-control" placeholder="Search friends">
</div>
<div class="empty-list-message">
<p>No friends online.</p>
</div>
</div>-->
</div>
</div>
<div class="g-col-8">
<div class="block transparent-override" id="market_list">
<div class="market">
<div class="spinner-grow text-glowing" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div id="market-carousel" class="carousel slide" style="display: none;">
<div class="carousel-indicators">
<button type="button" data-bs-target="#market-carousel" data-bs-slide-to="0" class="active" aria-current="true" aria-label="Slide 1"></button>
</div>
<div class="carousel-inner">
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#market-carousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#market-carousel" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
</div>
</div>
<div class="block" id="chat_list" style="margin-top: 15px;">
<div class="title chat-title">Chat <span>1337 online</span></div>
<div class="chat-history" style="display: none;">
<!-- <div class="chat-history-one">
<div class="chat-history-info">
<span class="time">2:54 </span>
<ion-icon name="arrow-undo-outline"></ion-icon>
</div>
<span>
<span class="chat-history-text chat-history-content-message">
<span class="formatter">
<a href="/profile/4764365" class="chat-history-user">
<span class="_nick">Chell</span>
</a>
<ion-icon name="remove-outline"></ion-icon>
<span>Hello </span>
<a href="/profile/3947788" class="chat-history-user">Disaster</a>
<span>: Lorem ipsum dolor sit amet </span>
</span>
</span>
</span>
</div> -->
</div>
<div class="message-input" style="display: none;">
<input type="text" class="form-control" maxlength="200" placeholder="Write a message and hit Enter" id="chat-message-input" autocomplete="off">
</div>
<div class="block-content" style="height: 280px; align-items: center;"> <div class="block-content" style="height: 280px; align-items: center;">
<div class="spinner-grow text-glowing" role="status"> <div class="spinner-grow text-glowing" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
@ -105,8 +553,74 @@
</div> </div>
</div> </div>
<div class="block" style="margin-top: 15px;"> <div class="block" id="waiting_list" style="margin-top: 15px;">
<div class="title">Waiting list</div> <div class="title">Waiting list<a data-bs-toggle="modal" data-bs-target="#game-creation-menu-modal" class="btn btn-primary navbar-btn">
<ion-icon name="dice-outline"></ion-icon>
<span>Create game</span>
</a></div>
<!--<div class="rooms-list">
<div class="games-room-one">
<div class="games-room-one-body">
<div class="games-room-one-body-head">
<div class="games-room-one-body-head-info">
<div class="_type">
<div>Fast game</div>
</div>
<div class="_with_wormhole">
<div>With portal</div>
</div>
</div>
<div class="games-room-one-body-head-actions"></div>
</div>
<div class="games-room-one-body-members">
<div class="games-room-one-body-members-one">
<div class="games-room-one-body-members-one-avatar" style="background-image: url(&quot;https://i.dogecdn.wtf/7lurfckMFrYXm4gf&quot;);">
<a href="/profile/822351"></a>
<div class="_online"></div>
</div>
<div class="games-room-one-body-members-one-nick">
<a href="/profile/822351">Wolf</a>
</div>
<div kd-tooltip-option-position="center" class="games-room-one-body-members-one-rank" style="background-image: url(&quot;//m1.dogecdn.wtf/ranks/0.svg&quot;);"></div>
</div>
<div class="games-room-one-body-members-one">
<div class="games-room-one-body-members-one-avatar" style="background-image: url(&quot;https://i.dogecdn.wtf/wxEpEiovduvcXadQ&quot;);">
<a href="/profile/4427427"></a>
<div class="_online"></div>
</div>
<div class="games-room-one-body-members-one-nick">
<a href="/profile/4427427">bolgovantonio</a>
</div>
<div kd-tooltip-option-position="center" class="games-room-one-body-members-one-rank" style="background-image: url(&quot;//m1.dogecdn.wtf/ranks/0.svg&quot;);"></div>
</div>
<div class="games-room-one-body-members-one _slot_join">
<div class="games-room-one-body-members-one-avatar">
<ion-icon name="add-outline" style="color: #656d78;"></ion-icon>
</div>
<div class="games-room-one-body-members-one-nick">
<span>Join</span>
</div>
</div>
<div class="games-room-one-body-members-one _slot_join">
<div class="games-room-one-body-members-one-avatar">
<ion-icon name="add-outline" style="color: #656d78;"></ion-icon>
</div>
<div class="games-room-one-body-members-one-nick">
<span>Join</span>
</div>
</div>
<div class="games-room-one-body-members-one _slot_join">
<div class="games-room-one-body-members-one-avatar">
<ion-icon name="add-outline" style="color: #656d78;"></ion-icon>
</div>
<div class="games-room-one-body-members-one-nick">
<span>Join</span>
</div>
</div>
</div>
</div>
</div>
</div>-->
<div class="block-content"> <div class="block-content">
<div class="spinner-grow text-glowing" role="status"> <div class="spinner-grow text-glowing" role="status">
<span class="visually-hidden">Loading...</span> <span class="visually-hidden">Loading...</span>
@ -117,5 +631,6 @@
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/essentials}"></th:block> <th:block th:insert="~{fragments/essentials}"></th:block>
<script src="/static/javascript/games.js"></script>
</body> </body>
</html> </html>

View File

@ -162,6 +162,8 @@
<script> <script>
$(document).ready(function() { $(document).ready(function() {
$(".navbar").removeClass("navbar-light"); $(".navbar").removeClass("navbar-light");
$(".navbar-brand-custom-plain").css("display", "");
$(".navbar-brand-custom-gradient").css("display", "none");
}); });
</script> </script>
</body> </body>