├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── README.md ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── cz │ │ └── jiripinkas │ │ └── jba │ │ ├── Application.java │ │ ├── WebXmlSpringBoot.java │ │ ├── annotation │ │ ├── DevProfile.java │ │ ├── UniqueBlog.java │ │ ├── UniqueBlogValidator.java │ │ ├── UniqueShortName.java │ │ ├── UniqueShortNameValidator.java │ │ ├── UniqueUsername.java │ │ └── UniqueUsernameValidator.java │ │ ├── atom │ │ ├── Entry.java │ │ ├── Feed.java │ │ ├── Link.java │ │ └── package-info.java │ │ ├── controller │ │ ├── BlogController.java │ │ ├── CategoryController.java │ │ ├── IconController.java │ │ ├── IndexController.java │ │ ├── LoginController.java │ │ ├── NewsController.java │ │ ├── RegisterController.java │ │ ├── SitemapController.java │ │ ├── SocialController.java │ │ ├── UserController.java │ │ └── admin │ │ │ ├── AdminCategoryController.java │ │ │ ├── AdminConfigurationController.java │ │ │ ├── AdminDetailController.java │ │ │ ├── AdminItemsController.java │ │ │ ├── AdminNewsController.java │ │ │ └── AdminUsersController.java │ │ ├── dto │ │ ├── BlogDto.java │ │ ├── CategoryDto.java │ │ └── ItemDto.java │ │ ├── entity │ │ ├── Blog.java │ │ ├── Category.java │ │ ├── Configuration.java │ │ ├── Item.java │ │ ├── NewsItem.java │ │ ├── Role.java │ │ └── User.java │ │ ├── exception │ │ ├── PageNotFoundException.java │ │ ├── RssException.java │ │ └── UrlException.java │ │ ├── repository │ │ ├── BlogRepository.java │ │ ├── CategoryRepository.java │ │ ├── ConfigurationRepository.java │ │ ├── ItemRepository.java │ │ ├── NewsItemRepository.java │ │ ├── RoleRepository.java │ │ └── UserRepository.java │ │ ├── rss │ │ ├── TRss.java │ │ ├── TRssChannel.java │ │ ├── TRssItem.java │ │ └── package-info.java │ │ ├── service │ │ ├── AllCategoriesService.java │ │ ├── BlogResultService.java │ │ ├── BlogService.java │ │ ├── CategoryService.java │ │ ├── ConfigurationInterceptor.java │ │ ├── ConfigurationService.java │ │ ├── ItemService.java │ │ ├── NewsService.java │ │ ├── RssService.java │ │ ├── UserService.java │ │ ├── initdb │ │ │ ├── HsqldbManagerService.java │ │ │ └── InitDbService.java │ │ └── scheduled │ │ │ └── ScheduledTasksService.java │ │ └── util │ │ └── MyUtil.java └── resources │ ├── apple-touch-icon.png │ ├── application-dev.properties │ ├── application-prod.properties │ ├── application-test.properties │ ├── application.properties │ ├── favicon.ico │ ├── generic-blog.png │ ├── java-logo.png │ ├── logback.xml │ ├── security.xml │ ├── static │ ├── favicon.ico │ ├── resources │ │ ├── css │ │ │ ├── bootstrap-dialog.min.css │ │ │ └── custom.css │ │ ├── img │ │ │ └── 404.jpg │ │ ├── js │ │ │ ├── account.js │ │ │ ├── admin-categories.js │ │ │ ├── ads.js │ │ │ ├── blogs.js │ │ │ ├── bootstrap-dialog.min.js │ │ │ ├── index.js │ │ │ ├── jquery.ba-throttle-debounce.min.js │ │ │ ├── jquery.cookie.js │ │ │ ├── jquery.unveil.js │ │ │ ├── main.js │ │ │ ├── news.js │ │ │ ├── register.js │ │ │ └── users.js │ │ └── prettyprint │ │ │ ├── lang-apollo.js │ │ │ ├── lang-basic.js │ │ │ ├── lang-clj.js │ │ │ ├── lang-css.js │ │ │ ├── lang-dart.js │ │ │ ├── lang-erlang.js │ │ │ ├── lang-go.js │ │ │ ├── lang-hs.js │ │ │ ├── lang-lisp.js │ │ │ ├── lang-llvm.js │ │ │ ├── lang-lua.js │ │ │ ├── lang-matlab.js │ │ │ ├── lang-ml.js │ │ │ ├── lang-mumps.js │ │ │ ├── lang-n.js │ │ │ ├── lang-pascal.js │ │ │ ├── lang-proto.js │ │ │ ├── lang-r.js │ │ │ ├── lang-rd.js │ │ │ ├── lang-scala.js │ │ │ ├── lang-sql.js │ │ │ ├── lang-tcl.js │ │ │ ├── lang-tex.js │ │ │ ├── lang-vb.js │ │ │ ├── lang-vhdl.js │ │ │ ├── lang-wiki.js │ │ │ ├── lang-xq.js │ │ │ ├── lang-yaml.js │ │ │ ├── prettify.css │ │ │ ├── prettify.js │ │ │ └── run_prettify.js │ └── yandex_60a2aaff053bad91.txt │ └── templates │ ├── account.html │ ├── admin-categories.html │ ├── admin-detail.html │ ├── blog-form.html │ ├── blogs.html │ ├── configuration.html │ ├── error │ └── 404.html │ ├── index.html │ ├── layout │ ├── footer.html │ ├── header.html │ └── other.html │ ├── login.html │ ├── news-detail.html │ ├── news-form.html │ ├── news.html │ ├── register.html │ ├── user-detail.html │ └── users.html └── test ├── java └── cz │ └── jiripinkas │ └── jba │ ├── service │ ├── AllTests.java │ ├── BlogServiceTest.java │ ├── ItemServiceTest.java │ ├── RssServiceTest.java │ └── scheduled │ │ └── ScheduledTasksServiceTest.java │ └── util │ └── MyUtilTest.java └── resources └── test-rss ├── baeldung.xml ├── dfetter.xml ├── hibernate.xml ├── instanceofjava.xml ├── javavids.xml ├── knitelius.xml ├── planetmysql.xml ├── reddit.com.json └── spring.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /debug*log 2 | /target/ 3 | .settings 4 | .classpath 5 | .project 6 | .springBeans 7 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Java Blog Aggregator: Boot

2 | 3 |

This application is a successor of original Java Blog Aggregator. It uses Spring boot and runs as a standalone JAR file, JSP and Tiles were switched to Thymeleaf and I organized JavaScript much better.

4 | 5 |

Development:

6 | 7 |

8 | Run with: -Dspring.profiles.active="dev" 9 |

10 | 11 |

12 | Will run on http://localhost:8080 with embedded HSQL database, username / password: admin / admin 13 |

14 | 15 |

Production:

16 | 17 |

18 | Packaging: mvn clean package -P prod 19 |

20 | 21 |

22 | Run: java -jar target/java-blog-aggregator.jar --spring.config.location=file:prod.properties --logging.config=file:logback-prod.xml 23 |

24 | 25 |

sample prod.properties contents:

26 | 27 |

28 | 29 | spring.profiles.active=prod
30 | server.port=8081
31 | spring.datasource.url=jdbc:postgresql://localhost:5432/DB_NAME
32 | spring.datasource.username=USERNAME
33 | spring.datasource.password=PASSWORD
34 | spring.datasource.driverClassName=org.postgresql.Driver
35 |
36 |

37 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/Application.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba; 2 | 3 | import ma.glasnost.orika.MapperFacade; 4 | import ma.glasnost.orika.impl.DefaultMapperFactory; 5 | import org.apache.http.impl.client.CloseableHttpClient; 6 | import org.apache.http.impl.client.HttpClients; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.boot.builder.SpringApplicationBuilder; 9 | import org.springframework.cache.CacheManager; 10 | import org.springframework.cache.annotation.EnableCaching; 11 | import org.springframework.cache.concurrent.ConcurrentMapCache; 12 | import org.springframework.cache.support.SimpleCacheManager; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.ImportResource; 15 | import org.springframework.scheduling.annotation.EnableScheduling; 16 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 17 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 18 | import org.springframework.web.client.RestTemplate; 19 | 20 | import java.util.Arrays; 21 | 22 | @ImportResource("classpath:security.xml") 23 | @SpringBootApplication 24 | @EnableCaching 25 | @EnableScheduling 26 | @EnableWebSecurity 27 | public class Application { 28 | 29 | public static void main(String[] args) { 30 | new SpringApplicationBuilder(Application.class).headless(false).run(args); 31 | } 32 | 33 | @Bean 34 | public MapperFacade dozerBeanMapper() { 35 | return new DefaultMapperFactory.Builder().build().getMapperFacade(); 36 | } 37 | 38 | @Bean 39 | public RestTemplate restTemplate() { 40 | return new RestTemplate(); 41 | } 42 | 43 | @Bean 44 | public CacheManager cacheManager() { 45 | SimpleCacheManager cacheManager = new SimpleCacheManager(); 46 | cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("icons"), new ConcurrentMapCache("configuration"), 47 | new ConcurrentMapCache("categories"), new ConcurrentMapCache("blogCount"), 48 | new ConcurrentMapCache("itemCount"), new ConcurrentMapCache("userCount"), 49 | new ConcurrentMapCache("blogCountUnapproved"))); 50 | return cacheManager; 51 | } 52 | 53 | @Bean(destroyMethod = "close") 54 | public CloseableHttpClient httpClient() { 55 | return HttpClients.createDefault(); 56 | } 57 | 58 | @Bean 59 | public ThreadPoolTaskScheduler scheduler() { 60 | ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); 61 | scheduler.setThreadPriority(Thread.MIN_PRIORITY); 62 | return scheduler; 63 | } 64 | 65 | // http://www.sporcic.org/2014/05/custom-error-pages-with-spring-boot/ 66 | // @Bean 67 | // public ConfigurableServletWebServerFactory containerCustomizer() { 68 | // 69 | // return new EmbeddedServletContainerCustomizer() { 70 | // @Override 71 | // public void customize(ConfigurableEmbeddedServletContainer container) { 72 | // ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/404"); 73 | // container.addErrorPages(error404Page); 74 | // container.addInitializers(new ServletContextInitializer() { 75 | // 76 | // @Override 77 | // public void onStartup(ServletContext servletContext) throws ServletException { 78 | // servletContext.setSessionTrackingModes(EnumSet.of(SessionTrackingMode.COOKIE)); 79 | // } 80 | // }); 81 | // } 82 | // }; 83 | // } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/WebXmlSpringBoot.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 | 9 | import cz.jiripinkas.jba.service.ConfigurationInterceptor; 10 | 11 | @Configuration 12 | public class WebXmlSpringBoot implements WebMvcConfigurer { 13 | 14 | @Autowired 15 | private ConfigurationInterceptor configurationInterceptor; 16 | 17 | @Override 18 | public void addInterceptors(InterceptorRegistry registry) { 19 | registry.addInterceptor(configurationInterceptor); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/DevProfile.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import org.springframework.context.annotation.Profile; 9 | 10 | @Profile("dev") 11 | @Retention(RetentionPolicy.RUNTIME) 12 | @Target({ ElementType.TYPE, ElementType.METHOD }) 13 | public @interface DevProfile { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/UniqueBlog.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import static java.lang.annotation.ElementType.FIELD; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import javax.validation.Constraint; 10 | import javax.validation.Payload; 11 | 12 | @Target({ FIELD }) 13 | @Retention(RUNTIME) 14 | @Constraint(validatedBy = { UniqueBlogValidator.class }) 15 | public @interface UniqueBlog { 16 | 17 | String message(); 18 | 19 | Class[] groups() default {}; 20 | 21 | Class[] payload() default {}; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/UniqueBlogValidator.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import cz.jiripinkas.jba.repository.BlogRepository; 9 | 10 | public class UniqueBlogValidator implements ConstraintValidator { 11 | 12 | @Autowired 13 | private BlogRepository blogRepository; 14 | 15 | @Override 16 | public void initialize(UniqueBlog constraintAnnotation) { 17 | } 18 | 19 | @Override 20 | public boolean isValid(String url, ConstraintValidatorContext context) { 21 | if(blogRepository == null) { 22 | return true; 23 | } 24 | return blogRepository.findByUrl(url) == null; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/UniqueShortName.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import static java.lang.annotation.ElementType.FIELD; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import javax.validation.Constraint; 10 | import javax.validation.Payload; 11 | 12 | @Target({ FIELD }) 13 | @Retention(RUNTIME) 14 | @Constraint(validatedBy = { UniqueShortNameValidator.class }) 15 | public @interface UniqueShortName { 16 | 17 | String message(); 18 | 19 | Class[] groups() default {}; 20 | 21 | Class[] payload() default {}; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/UniqueShortNameValidator.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import cz.jiripinkas.jba.repository.BlogRepository; 9 | import cz.jiripinkas.jba.util.MyUtil; 10 | 11 | public class UniqueShortNameValidator implements ConstraintValidator { 12 | 13 | @Autowired 14 | private BlogRepository blogRepository; 15 | 16 | @Override 17 | public void initialize(UniqueShortName constraintAnnotation) { 18 | } 19 | 20 | @Override 21 | public boolean isValid(String shortName, ConstraintValidatorContext context) { 22 | if(blogRepository == null) { 23 | return true; 24 | } 25 | return blogRepository.findByShortName(MyUtil.generatePermalink(shortName)) == null; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/UniqueUsername.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import static java.lang.annotation.ElementType.FIELD; 4 | import static java.lang.annotation.RetentionPolicy.RUNTIME; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.Target; 8 | 9 | import javax.validation.Constraint; 10 | import javax.validation.Payload; 11 | 12 | @Target({ FIELD }) 13 | @Retention(RUNTIME) 14 | @Constraint(validatedBy = { UniqueUsernameValidator.class }) 15 | public @interface UniqueUsername { 16 | 17 | String message(); 18 | 19 | Class[] groups() default {}; 20 | 21 | Class[] payload() default {}; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/annotation/UniqueUsernameValidator.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.annotation; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | 8 | import cz.jiripinkas.jba.repository.UserRepository; 9 | 10 | public class UniqueUsernameValidator implements ConstraintValidator { 11 | 12 | @Autowired 13 | private UserRepository userRepository; 14 | 15 | @Override 16 | public void initialize(UniqueUsername constraintAnnotation) { 17 | } 18 | 19 | @Override 20 | public boolean isValid(String username, ConstraintValidatorContext context) { 21 | if(userRepository == null) { 22 | return true; 23 | } 24 | return userRepository.findByName(username) == null; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/atom/Entry.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.atom; 2 | 3 | import java.util.List; 4 | 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlElement; 8 | import javax.xml.datatype.XMLGregorianCalendar; 9 | 10 | @XmlAccessorType(XmlAccessType.FIELD) 11 | public class Entry { 12 | 13 | private String title; 14 | 15 | @XmlElement(name = "link") 16 | private List links; 17 | 18 | @XmlElement(namespace = "http://rssnamespace.org/feedburner/ext/1.0") 19 | private String origLink; 20 | 21 | private XMLGregorianCalendar updated; 22 | 23 | private XMLGregorianCalendar published; 24 | 25 | private String content; 26 | 27 | private String summary; 28 | 29 | public String getOrigLink() { 30 | return origLink; 31 | } 32 | 33 | public void setOrigLink(String origLink) { 34 | this.origLink = origLink; 35 | } 36 | 37 | public XMLGregorianCalendar getPublished() { 38 | return published; 39 | } 40 | 41 | public void setPublished(XMLGregorianCalendar published) { 42 | this.published = published; 43 | } 44 | 45 | public String getSummary() { 46 | return summary; 47 | } 48 | 49 | public void setSummary(String summary) { 50 | this.summary = summary; 51 | } 52 | 53 | public String getTitle() { 54 | return title; 55 | } 56 | 57 | public void setTitle(String title) { 58 | this.title = title; 59 | } 60 | 61 | public List getLinks() { 62 | return links; 63 | } 64 | 65 | public void setLinks(List links) { 66 | this.links = links; 67 | } 68 | 69 | public String getContent() { 70 | return content; 71 | } 72 | 73 | public XMLGregorianCalendar getUpdated() { 74 | return updated; 75 | } 76 | 77 | public void setUpdated(XMLGregorianCalendar updated) { 78 | this.updated = updated; 79 | } 80 | 81 | public void setContent(String content) { 82 | this.content = content; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/atom/Feed.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.atom; 2 | 3 | import java.util.List; 4 | 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlElement; 8 | import javax.xml.bind.annotation.XmlRootElement; 9 | 10 | @XmlRootElement 11 | @XmlAccessorType(XmlAccessType.FIELD) 12 | public class Feed { 13 | 14 | @XmlElement(name = "entry") 15 | private List entries; 16 | 17 | public List getEntries() { 18 | return entries; 19 | } 20 | 21 | public void setEntries(List entries) { 22 | this.entries = entries; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/atom/Link.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.atom; 2 | 3 | import javax.xml.bind.annotation.XmlAccessType; 4 | import javax.xml.bind.annotation.XmlAccessorType; 5 | import javax.xml.bind.annotation.XmlAttribute; 6 | 7 | @XmlAccessorType(XmlAccessType.FIELD) 8 | public class Link { 9 | 10 | @XmlAttribute 11 | private String rel; 12 | 13 | @XmlAttribute 14 | private String href; 15 | 16 | public String getRel() { 17 | return rel; 18 | } 19 | 20 | public void setRel(String rel) { 21 | this.rel = rel; 22 | } 23 | 24 | public String getHref() { 25 | return href; 26 | } 27 | 28 | public void setHref(String href) { 29 | this.href = href; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/atom/package-info.java: -------------------------------------------------------------------------------- 1 | @XmlSchema(namespace = "http://www.w3.org/2005/Atom", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = { @XmlNs(prefix = "feedburner", namespaceURI = "http://rssnamespace.org/feedburner/ext/1.0") }) 2 | package cz.jiripinkas.jba.atom; 3 | 4 | import javax.xml.bind.annotation.XmlNs; 5 | import javax.xml.bind.annotation.XmlNsForm; 6 | import javax.xml.bind.annotation.XmlSchema; 7 | 8 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/BlogController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.ui.Model; 13 | import org.springframework.web.bind.annotation.ExceptionHandler; 14 | import org.springframework.web.bind.annotation.PathVariable; 15 | import org.springframework.web.bind.annotation.RequestHeader; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RequestParam; 18 | import org.springframework.web.bind.annotation.ResponseBody; 19 | 20 | import cz.jiripinkas.jba.entity.Blog; 21 | import cz.jiripinkas.jba.exception.PageNotFoundException; 22 | import cz.jiripinkas.jba.service.BlogService; 23 | import cz.jiripinkas.jba.service.ItemService; 24 | import cz.jiripinkas.jba.service.ItemService.MaxType; 25 | import cz.jiripinkas.jba.service.ItemService.OrderType; 26 | import cz.jiripinkas.jba.util.MyUtil; 27 | 28 | @Controller 29 | public class BlogController { 30 | 31 | private static final Logger log = LoggerFactory.getLogger(BlogController.class); 32 | 33 | @Autowired 34 | private ItemService itemService; 35 | 36 | @Autowired 37 | private BlogService blogService; 38 | 39 | @ExceptionHandler 40 | public void handleBlogNotFound(PageNotFoundException exception, HttpServletResponse response) throws IOException { 41 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 42 | } 43 | 44 | private void findBlog(String shortName, Model model) { 45 | Blog blog = blogService.findByShortName(shortName); 46 | if (blog == null) { 47 | log.error("Blog not found {}", shortName); 48 | throw new PageNotFoundException(); 49 | } 50 | model.addAttribute("title", "Blog: " + blog.getPublicName()); 51 | model.addAttribute("blogDetail", true); 52 | model.addAttribute("blogShortName", blog.getShortName()); 53 | model.addAttribute("blog", blog); 54 | } 55 | 56 | @RequestMapping(value = "/blog/{shortName}") 57 | public String blogDetail(Model model, HttpServletRequest request, @RequestParam(defaultValue = "0") Integer page, @PathVariable String shortName, @RequestParam(required = false) String orderBy, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 58 | log.info("UA: {}", userAgent); 59 | log.info("Navigated to blog: {}, page: {}", shortName, page); 60 | findBlog(shortName, model); 61 | return showPage(model, page, shortName, request, orderBy); 62 | } 63 | 64 | private String showPage(Model model, int page, String shortName, HttpServletRequest request, String orderBy) { 65 | boolean showAll = false; 66 | if (request.isUserInRole("ADMIN")) { 67 | showAll = true; 68 | } 69 | OrderType orderType = OrderType.LATEST; 70 | if (orderBy != null && orderBy.contains("top")) { 71 | orderType = OrderType.MOST_VIEWED; 72 | } 73 | MaxType maxType = MaxType.UNDEFINED; 74 | if (orderBy != null && orderBy.toLowerCase().contains("month")) { 75 | maxType = MaxType.MONTH; 76 | } else if (orderBy != null && orderBy.toLowerCase().contains("week")) { 77 | maxType = MaxType.WEEK; 78 | } 79 | model.addAttribute("items", itemService.getDtoItems(page, showAll, orderType, maxType, null, null, shortName)); 80 | model.addAttribute("nextPage", page + 1); 81 | return "index"; 82 | } 83 | 84 | @RequestMapping("/blogs") 85 | public String showBlogs(Model model, HttpServletRequest request, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 86 | log.info("UA: {}", userAgent); 87 | log.info("Navigated to blogs list"); 88 | boolean showAll = false; 89 | if (request.isUserInRole("ADMIN")) { 90 | showAll = true; 91 | } 92 | model.addAttribute("blogs", blogService.findAll(showAll)); 93 | model.addAttribute("current", "blogs"); 94 | return "blogs"; 95 | } 96 | 97 | @RequestMapping("/blog/shortname/available") 98 | @ResponseBody 99 | public String available(@RequestParam String shortName) { 100 | Boolean available = blogService.findByShortName(MyUtil.generatePermalink(shortName)) == null; 101 | return available.toString(); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/CategoryController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import cz.jiripinkas.jba.service.AllCategoriesService; 9 | 10 | @Controller 11 | public class CategoryController { 12 | 13 | @Autowired 14 | private AllCategoriesService allCategoriesService; 15 | 16 | @RequestMapping("/all-categories") 17 | @ResponseBody 18 | public Integer[] getCategories() { 19 | return allCategoriesService.getAllCategoryIds(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/IconController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.http.HttpServletResponse; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.ResponseBody; 16 | 17 | import cz.jiripinkas.jba.exception.PageNotFoundException; 18 | import cz.jiripinkas.jba.service.BlogService; 19 | import cz.jiripinkas.jba.service.ConfigurationService; 20 | 21 | @Controller 22 | @RequestMapping(value = "/spring/icon", produces = MediaType.IMAGE_PNG_VALUE) 23 | public class IconController { 24 | 25 | private static final Logger log = LoggerFactory.getLogger(IconController.class); 26 | 27 | @Autowired 28 | private BlogService blogService; 29 | 30 | @Autowired 31 | private ConfigurationService configurationService; 32 | 33 | @ExceptionHandler(PageNotFoundException.class) 34 | public void pageNotFound(HttpServletResponse response) throws IOException { 35 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 36 | } 37 | 38 | @ResponseBody 39 | @RequestMapping 40 | public byte[] getIcon() throws IOException { 41 | return configurationService.find().getIcon(); 42 | } 43 | 44 | @ResponseBody 45 | @RequestMapping(value = "/{blogId}") 46 | public byte[] getBlogIcon(@PathVariable int blogId) throws IOException { 47 | try { 48 | return blogService.getIcon(blogId); 49 | } catch (PageNotFoundException e) { 50 | log.error("Icon not found! Blog id: {}", blogId); 51 | throw e; 52 | } 53 | } 54 | 55 | @ResponseBody 56 | @RequestMapping(value = "/favicon") 57 | public byte[] getFavicon() throws IOException { 58 | return configurationService.find().getFavicon(); 59 | } 60 | 61 | @ResponseBody 62 | @RequestMapping(value = "/appleTouchIcon") 63 | public byte[] getAppleTouchIcon() throws IOException { 64 | return configurationService.find().getAppleTouchIcon(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/LoginController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.ui.Model; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | @Controller 8 | public class LoginController { 9 | 10 | @RequestMapping("/login") 11 | public String login(Model model) { 12 | model.addAttribute("current", "login"); 13 | return "login"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/NewsController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.http.HttpServletResponse; 6 | 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.ui.Model; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RequestHeader; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RequestParam; 17 | import org.springframework.web.bind.annotation.ResponseBody; 18 | 19 | import cz.jiripinkas.jba.entity.NewsItem; 20 | import cz.jiripinkas.jba.exception.PageNotFoundException; 21 | import cz.jiripinkas.jba.service.NewsService; 22 | 23 | @Controller 24 | @RequestMapping("/news") 25 | public class NewsController { 26 | 27 | private static final Logger log = LoggerFactory.getLogger(NewsController.class); 28 | 29 | @Autowired 30 | private NewsService newsService; 31 | 32 | @ExceptionHandler(PageNotFoundException.class) 33 | public void pageNotFound(HttpServletResponse response) throws IOException { 34 | response.sendError(HttpServletResponse.SC_NOT_FOUND); 35 | } 36 | 37 | @RequestMapping 38 | public String showNews(Model model, @RequestParam(defaultValue = "0") int page, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 39 | log.info("UA: {}", userAgent); 40 | log.info("Navigated to news list"); 41 | model.addAttribute("newsPage", newsService.findNews(page)); 42 | model.addAttribute("currPage", page); 43 | model.addAttribute("current", "news"); 44 | return "news"; 45 | } 46 | 47 | @RequestMapping("/{shortName}") 48 | public String showDetail(Model model, @PathVariable String shortName, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 49 | log.info("UA: {}", userAgent); 50 | log.info("Navigated to news: {}", shortName); 51 | NewsItem newsItem = newsService.findOne(shortName); 52 | if(newsItem == null) { 53 | log.error("News not found: {}", shortName); 54 | throw new PageNotFoundException(); 55 | } 56 | model.addAttribute("news", newsItem); 57 | model.addAttribute("current", "news"); 58 | return "news-detail"; 59 | } 60 | 61 | @ResponseBody 62 | @RequestMapping("/feed.xml") 63 | public String rss(@RequestHeader(value = "User-Agent", required = false) String userAgent) { 64 | log.info("UA: {}", userAgent); 65 | log.info("Navigated to rss feed"); 66 | return newsService.getFeed(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/RegisterController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import javax.validation.Valid; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.validation.BindingResult; 9 | import org.springframework.web.bind.annotation.ModelAttribute; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | import org.springframework.web.servlet.ModelAndView; 15 | import org.springframework.web.servlet.view.RedirectView; 16 | 17 | import cz.jiripinkas.jba.entity.User; 18 | import cz.jiripinkas.jba.service.UserService; 19 | 20 | @Controller 21 | @RequestMapping("/register") 22 | public class RegisterController { 23 | 24 | @Autowired 25 | private UserService userService; 26 | 27 | @ModelAttribute("user") 28 | public User constructUser() { 29 | return new User(); 30 | } 31 | 32 | @RequestMapping 33 | public String showRegister(Model model) { 34 | model.addAttribute("current", "register"); 35 | return "register"; 36 | } 37 | 38 | @RequestMapping(method = RequestMethod.POST) 39 | public ModelAndView doRegister(@Valid @ModelAttribute("user") User user, BindingResult result) { 40 | if (result.hasErrors()) { 41 | return new ModelAndView("register"); 42 | } 43 | userService.save(user); 44 | RedirectView redirectView = new RedirectView("/register?success=true"); 45 | redirectView.setExposeModelAttributes(false); 46 | return new ModelAndView(redirectView); 47 | } 48 | 49 | @RequestMapping("/available") 50 | @ResponseBody 51 | public String available(@RequestParam String username) { 52 | Boolean available = userService.findOne(username) == null; 53 | return available.toString(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/SitemapController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.ResponseBody; 7 | 8 | import cz.jiripinkas.jba.entity.Blog; 9 | import cz.jiripinkas.jba.entity.Configuration; 10 | import cz.jiripinkas.jba.entity.NewsItem; 11 | import cz.jiripinkas.jba.service.BlogService; 12 | import cz.jiripinkas.jba.service.ConfigurationService; 13 | import cz.jiripinkas.jba.service.NewsService; 14 | import cz.jiripinkas.jsitemapgenerator.WebPage; 15 | import cz.jiripinkas.jsitemapgenerator.generator.SitemapGenerator; 16 | 17 | @Controller 18 | public class SitemapController { 19 | 20 | @Autowired 21 | private ConfigurationService configurationService; 22 | 23 | @Autowired 24 | private BlogService blogService; 25 | 26 | @Autowired 27 | private NewsService newsService; 28 | 29 | @ResponseBody 30 | @RequestMapping("/robots.txt") 31 | public String getRobots() { 32 | StringBuilder stringBuilder = new StringBuilder(); 33 | stringBuilder.append("Sitemap: "); 34 | stringBuilder.append(configurationService.find().getChannelLink()); 35 | stringBuilder.append("/sitemap.xml"); 36 | stringBuilder.append("\n"); 37 | stringBuilder.append("User-agent: *"); 38 | stringBuilder.append("\n"); 39 | stringBuilder.append("Allow: /"); 40 | stringBuilder.append("\n"); 41 | return stringBuilder.toString(); 42 | } 43 | 44 | @ResponseBody 45 | @RequestMapping("/sitemap") 46 | public String getSitemap() { 47 | Configuration configuration = configurationService.find(); 48 | SitemapGenerator sitemapGenerator = new SitemapGenerator(configuration.getChannelLink()); 49 | sitemapGenerator.addPage(new WebPage().setName("")); 50 | sitemapGenerator.addPage(new WebPage().setName("blogs")); 51 | sitemapGenerator.addPage(new WebPage().setName("news")); 52 | for (Blog blog : blogService.findAll(false)) { 53 | sitemapGenerator.addPage(new WebPage().setName("blog/" + blog.getShortName())); 54 | } 55 | for (NewsItem newsItem : newsService.findAll()) { 56 | sitemapGenerator.addPage(new WebPage().setName("news/" + newsItem.getShortName())); 57 | } 58 | return sitemapGenerator.constructSitemapString(); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/SocialController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.RequestHeader; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestMethod; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | 13 | import cz.jiripinkas.jba.service.ItemService; 14 | 15 | @Controller 16 | @RequestMapping("/social") 17 | public class SocialController { 18 | 19 | private static final Logger log = LoggerFactory.getLogger(SocialController.class); 20 | 21 | @Autowired 22 | private ItemService itemService; 23 | 24 | @RequestMapping(value = "/like", method = RequestMethod.POST) 25 | @ResponseBody 26 | public String like(@RequestParam int itemId, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 27 | log.info("UA: {}", userAgent); 28 | log.info("Inc like to item with id: {}", itemId); 29 | return Integer.toString(itemService.incLike(itemId)); 30 | } 31 | 32 | @RequestMapping(value = "/unlike", method = RequestMethod.POST) 33 | @ResponseBody 34 | public String unlike(@RequestParam int itemId, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 35 | log.info("UA: {}", userAgent); 36 | log.info("Dec like to item with id: {}", itemId); 37 | return Integer.toString(itemService.decLike(itemId)); 38 | } 39 | 40 | @RequestMapping(value = "/dislike", method = RequestMethod.POST) 41 | @ResponseBody 42 | public String dislike(@RequestParam int itemId, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 43 | log.info("UA: {}", userAgent); 44 | log.info("Inc dislike to item with id: {}", itemId); 45 | return Integer.toString(itemService.incDislike(itemId)); 46 | } 47 | 48 | @RequestMapping(value = "/undislike", method = RequestMethod.POST) 49 | @ResponseBody 50 | public String undislike(@RequestParam int itemId, @RequestHeader(value = "User-Agent", required = false) String userAgent) { 51 | log.info("UA: {}", userAgent); 52 | log.info("Dec dislike to item with id: {}", itemId); 53 | return Integer.toString(itemService.decDislike(itemId)); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller; 2 | 3 | import java.security.Principal; 4 | 5 | import javax.servlet.http.HttpServletRequest; 6 | import javax.validation.Valid; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.ui.Model; 11 | import org.springframework.validation.BindingResult; 12 | import org.springframework.web.bind.annotation.ModelAttribute; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RequestMapping; 15 | import org.springframework.web.bind.annotation.RequestMethod; 16 | import org.springframework.web.bind.annotation.RequestParam; 17 | import org.springframework.web.bind.annotation.ResponseBody; 18 | import org.springframework.web.servlet.ModelAndView; 19 | import org.springframework.web.servlet.View; 20 | import org.springframework.web.servlet.view.RedirectView; 21 | 22 | import cz.jiripinkas.jba.entity.Blog; 23 | import cz.jiripinkas.jba.service.BlogService; 24 | import cz.jiripinkas.jba.service.UserService; 25 | 26 | @Controller 27 | public class UserController { 28 | 29 | @Autowired 30 | private UserService userService; 31 | 32 | @Autowired 33 | private BlogService blogService; 34 | 35 | @ModelAttribute("blog") 36 | public Blog constructBlog() { 37 | Blog blog = new Blog(); 38 | blog.setMinRedditUps(0); 39 | return blog; 40 | } 41 | 42 | @RequestMapping("/blog-form") 43 | public String showForm(@RequestParam int blogId, Model model) { 44 | model.addAttribute("blog", blogService.findOne(blogId)); 45 | return "blog-form"; 46 | } 47 | 48 | @RequestMapping(value = "/blog-form", method = RequestMethod.POST) 49 | public View editBlog(@RequestParam int blogId, @ModelAttribute Blog blog, Model model, Principal principal, HttpServletRequest request) { 50 | blog.setId(blogId); 51 | blogService.update(blog, principal.getName(), request.isUserInRole("ADMIN")); 52 | RedirectView redirectView = new RedirectView("blog-form?blogId=" + blogId + "&success=true"); 53 | redirectView.setExposeModelAttributes(false); 54 | return redirectView; 55 | } 56 | 57 | @RequestMapping("/account") 58 | public String account(Model model, Principal principal) { 59 | String name = principal.getName(); 60 | model.addAttribute("user", userService.findOneWithBlogs(name)); 61 | model.addAttribute("current", "account"); 62 | return "account"; 63 | } 64 | 65 | @RequestMapping(value = "/account", method = RequestMethod.POST) 66 | public ModelAndView doAddBlog(Model model, @Valid @ModelAttribute("blog") Blog blog, BindingResult result, Principal principal) { 67 | if (result.hasErrors()) { 68 | return new ModelAndView(account(model, principal)); 69 | } 70 | String name = principal.getName(); 71 | blogService.save(blog, name); 72 | RedirectView redirectView = new RedirectView("/account?success=true"); 73 | redirectView.setExposeModelAttributes(false); 74 | return new ModelAndView(redirectView); 75 | } 76 | 77 | @RequestMapping(value = "/blog/remove/{id}", method = RequestMethod.POST) 78 | public View removeBlog(@PathVariable int id) { 79 | Blog blog = blogService.findOneFetchUser(id); 80 | blogService.delete(blog); 81 | RedirectView redirectView = new RedirectView("/account?success=true"); 82 | redirectView.setExposeModelAttributes(false); 83 | return redirectView; 84 | } 85 | 86 | @RequestMapping("/blog/available") 87 | @ResponseBody 88 | public String available(@RequestParam String url) { 89 | Boolean available = blogService.findOne(url) == null; 90 | return available.toString(); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/admin/AdminCategoryController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller.admin; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.HttpStatus; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.ModelAttribute; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.ResponseBody; 12 | import org.springframework.web.bind.annotation.ResponseStatus; 13 | import org.springframework.web.servlet.View; 14 | import org.springframework.web.servlet.view.RedirectView; 15 | 16 | import cz.jiripinkas.jba.dto.CategoryDto; 17 | import cz.jiripinkas.jba.entity.Category; 18 | import cz.jiripinkas.jba.service.CategoryService; 19 | 20 | @Controller 21 | @RequestMapping("/admin/categories") 22 | public class AdminCategoryController { 23 | 24 | @Autowired 25 | private CategoryService categoryService; 26 | 27 | @RequestMapping 28 | public String categories(Model model) { 29 | model.addAttribute("categories", categoryService.findAll()); 30 | model.addAttribute("current", "admin-categories"); 31 | return "admin-categories"; 32 | } 33 | 34 | @ModelAttribute 35 | public Category construct() { 36 | return new Category(); 37 | } 38 | 39 | @RequestMapping(method = RequestMethod.POST) 40 | public View save(@ModelAttribute Category category) { 41 | categoryService.save(category); 42 | RedirectView redirectView = new RedirectView("categories"); 43 | redirectView.setExposeModelAttributes(false); 44 | return redirectView; 45 | } 46 | 47 | @ResponseStatus(HttpStatus.OK) 48 | @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) 49 | public void delete(@PathVariable int id) { 50 | categoryService.delete(id); 51 | } 52 | 53 | @ResponseBody 54 | @RequestMapping("/{id}") 55 | public CategoryDto categoryShortName(@PathVariable int id) { 56 | return categoryService.findOneDto(id); 57 | } 58 | 59 | @ResponseBody 60 | @RequestMapping(value = "/set/{blogId}/cat/{categoryId}", method = RequestMethod.POST) 61 | public String setMapping(@PathVariable int blogId, @PathVariable int categoryId) { 62 | categoryService.addMapping(blogId, categoryId); 63 | return "ok"; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/admin/AdminConfigurationController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller.admin; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.web.bind.annotation.ModelAttribute; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.RequestParam; 12 | import org.springframework.web.multipart.MultipartFile; 13 | import org.springframework.web.servlet.View; 14 | import org.springframework.web.servlet.view.RedirectView; 15 | 16 | import cz.jiripinkas.jba.entity.Configuration; 17 | import cz.jiripinkas.jba.service.ConfigurationService; 18 | 19 | @RequestMapping("/admin/configuration") 20 | @Controller 21 | public class AdminConfigurationController { 22 | 23 | private static final Logger log = LoggerFactory.getLogger(AdminConfigurationController.class); 24 | 25 | @Autowired 26 | private ConfigurationService configurationService; 27 | 28 | @RequestMapping 29 | public String show(Model model) { 30 | model.addAttribute("configuration", configurationService.find()); 31 | model.addAttribute("current", "configuration"); 32 | return "configuration"; 33 | } 34 | 35 | @RequestMapping(method = RequestMethod.POST) 36 | public View save(@ModelAttribute Configuration configuration) { 37 | configurationService.save(configuration); 38 | RedirectView redirectView = new RedirectView("configuration?success=true"); 39 | redirectView.setExposeModelAttributes(false); 40 | return redirectView; 41 | } 42 | 43 | @RequestMapping(value = "/upload-icon", method = RequestMethod.POST) 44 | public View uploadIcon(@RequestParam MultipartFile icon) { 45 | if (!icon.isEmpty()) { 46 | try { 47 | log.info("save icon"); 48 | configurationService.saveIcon(icon.getBytes()); 49 | } catch (Exception e) { 50 | log.error("could not upload icon", e); 51 | } 52 | } else { 53 | log.error("could not upload icon"); 54 | } 55 | RedirectView redirectView = new RedirectView("?success=true"); 56 | redirectView.setExposeModelAttributes(false); 57 | return redirectView; 58 | } 59 | 60 | @RequestMapping(value = "/upload-favicon", method = RequestMethod.POST) 61 | public View uploadFavicon(@RequestParam MultipartFile favicon) { 62 | if (!favicon.isEmpty()) { 63 | try { 64 | log.info("save favicon"); 65 | configurationService.saveFavicon(favicon.getBytes()); 66 | } catch (Exception e) { 67 | log.error("could not upload favicon", e); 68 | } 69 | } else { 70 | log.error("could not upload favicon"); 71 | } 72 | RedirectView redirectView = new RedirectView("?success=true"); 73 | redirectView.setExposeModelAttributes(false); 74 | return redirectView; 75 | } 76 | 77 | @RequestMapping(value = "/upload-appleTouchIcon", method = RequestMethod.POST) 78 | public View uploadAppleTouchIcon(@RequestParam MultipartFile appleTouchIcon) { 79 | if (!appleTouchIcon.isEmpty()) { 80 | try { 81 | log.info("save apple touch icon"); 82 | configurationService.saveAppleTouchIcon(appleTouchIcon.getBytes()); 83 | } catch (Exception e) { 84 | log.error("could not upload appleTouchIcon", e); 85 | } 86 | } else { 87 | log.error("could not upload appleTouchIcon"); 88 | } 89 | RedirectView redirectView = new RedirectView("?success=true"); 90 | redirectView.setExposeModelAttributes(false); 91 | return redirectView; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/admin/AdminDetailController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller.admin; 2 | 3 | import javax.validation.Valid; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.ui.Model; 8 | import org.springframework.validation.BindingResult; 9 | import org.springframework.web.bind.annotation.ModelAttribute; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.servlet.ModelAndView; 13 | import org.springframework.web.servlet.view.RedirectView; 14 | 15 | import cz.jiripinkas.jba.entity.User; 16 | import cz.jiripinkas.jba.service.UserService; 17 | 18 | @Controller 19 | @RequestMapping("/admin/detail") 20 | public class AdminDetailController { 21 | 22 | @Autowired 23 | private UserService userService; 24 | 25 | @RequestMapping 26 | public String show(Model model) { 27 | model.addAttribute("user", userService.findAdmin()); 28 | model.addAttribute("current", "admin-detail"); 29 | return "admin-detail"; 30 | } 31 | 32 | @RequestMapping(method = RequestMethod.POST) 33 | public ModelAndView save(@ModelAttribute @Valid User user, BindingResult bindingResult) { 34 | if (bindingResult.hasErrors()) { 35 | return new ModelAndView("admin-detail"); 36 | } 37 | userService.saveAdmin(user); 38 | RedirectView redirectView = new RedirectView("detail?success=true"); 39 | redirectView.setExposeModelAttributes(false); 40 | return new ModelAndView(redirectView); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/admin/AdminItemsController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller.admin; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.ResponseBody; 8 | 9 | import cz.jiripinkas.jba.service.ItemService; 10 | 11 | @Controller 12 | public class AdminItemsController { 13 | 14 | @Autowired 15 | private ItemService itemService; 16 | 17 | @RequestMapping("/admin/items/toggle-enabled/{id}") 18 | @ResponseBody 19 | public String toggleEnabled(@PathVariable int id) { 20 | boolean enabled = itemService.toggleEnabled(id); 21 | return Boolean.toString(enabled); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/admin/AdminNewsController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller.admin; 2 | 3 | import javax.validation.Valid; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.ModelAttribute; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestMethod; 13 | import org.springframework.web.bind.annotation.ResponseStatus; 14 | import org.springframework.web.servlet.View; 15 | import org.springframework.web.servlet.view.RedirectView; 16 | 17 | import cz.jiripinkas.jba.entity.NewsItem; 18 | import cz.jiripinkas.jba.service.NewsService; 19 | 20 | @Controller 21 | @RequestMapping("/admin/news") 22 | public class AdminNewsController { 23 | 24 | @Autowired 25 | private NewsService newsService; 26 | 27 | @ModelAttribute 28 | public NewsItem construct() { 29 | return new NewsItem(); 30 | } 31 | 32 | @RequestMapping("/add") 33 | public String showAdd(Model model) { 34 | NewsItem newsItem = new NewsItem(); 35 | newsItem.setDescription("
\n\n
\n"); 36 | model.addAttribute("newsItem", newsItem); 37 | model.addAttribute("current", "news-form"); 38 | return "news-form"; 39 | } 40 | 41 | @RequestMapping(value = "/add", method = RequestMethod.POST) 42 | public View insert(@Valid @ModelAttribute NewsItem newsItem) { 43 | newsService.save(newsItem); 44 | RedirectView redirectView = new RedirectView("../news/add?success=true"); 45 | redirectView.setExposeModelAttributes(false); 46 | return redirectView; 47 | } 48 | 49 | @RequestMapping("/edit/{shortName}") 50 | public String showEdit(Model model, @PathVariable String shortName) { 51 | model.addAttribute("newsItem", newsService.findOne(shortName)); 52 | return "news-form"; 53 | } 54 | 55 | @RequestMapping(value = "/edit/{shortName}", method = RequestMethod.POST) 56 | public View edit(@Valid @ModelAttribute NewsItem newsItem) { 57 | newsService.save(newsItem); 58 | RedirectView redirectView = new RedirectView(newsItem.getShortName() + "?success=true"); 59 | redirectView.setExposeModelAttributes(false); 60 | return redirectView; 61 | } 62 | 63 | @ResponseStatus(HttpStatus.OK) 64 | @RequestMapping(value = "/delete/{id}", method = RequestMethod.POST) 65 | public void delete(@PathVariable int id) { 66 | newsService.delete(id); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/controller/admin/AdminUsersController.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.controller.admin; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.stereotype.Controller; 8 | import org.springframework.ui.Model; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | import org.springframework.web.bind.annotation.ResponseStatus; 14 | import org.springframework.web.multipart.MultipartFile; 15 | import org.springframework.web.servlet.View; 16 | import org.springframework.web.servlet.view.RedirectView; 17 | 18 | import cz.jiripinkas.jba.service.BlogService; 19 | import cz.jiripinkas.jba.service.UserService; 20 | 21 | @Controller 22 | @RequestMapping("/admin/users") 23 | public class AdminUsersController { 24 | 25 | private static final Logger log = LoggerFactory.getLogger(AdminUsersController.class); 26 | 27 | @Autowired 28 | private UserService userService; 29 | 30 | @Autowired 31 | private BlogService blogService; 32 | 33 | @RequestMapping 34 | public String users(Model model) { 35 | model.addAttribute("users", userService.findAll()); 36 | model.addAttribute("current", "users"); 37 | return "users"; 38 | } 39 | 40 | @RequestMapping("/{id}") 41 | public String detail(Model model, @PathVariable int id) { 42 | model.addAttribute("user", userService.findOneWithBlogs(id)); 43 | return "user-detail"; 44 | } 45 | 46 | @ResponseStatus(HttpStatus.OK) 47 | @RequestMapping(value = "/remove/{id}", method = RequestMethod.POST) 48 | public void removeUser(@PathVariable int id) { 49 | userService.delete(id); 50 | } 51 | 52 | @RequestMapping(value = "/upload-icon/{id}", method = RequestMethod.POST) 53 | public View uploadIcon(@RequestParam MultipartFile icon, @PathVariable("id") int blogId) { 54 | if (!icon.isEmpty()) { 55 | try { 56 | blogService.saveIcon(blogId, icon.getBytes()); 57 | } catch (Exception e) { 58 | log.error("could not upload icon", e); 59 | } 60 | } else { 61 | log.error("could not upload icon"); 62 | } 63 | RedirectView redirectView = new RedirectView("/blog-form?blogId=" + blogId + "&success=true"); 64 | redirectView.setExposeModelAttributes(false); 65 | return redirectView; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/dto/BlogDto.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.dto; 2 | 3 | import cz.jiripinkas.jba.util.MyUtil; 4 | 5 | public class BlogDto { 6 | 7 | private String name; 8 | 9 | private String nick; 10 | 11 | private String shortName; 12 | 13 | private int id; 14 | 15 | private CategoryDto category; 16 | 17 | public String getPublicName() { 18 | return MyUtil.getPublicName(nick, name, true); 19 | } 20 | 21 | public CategoryDto getCategory() { 22 | return category; 23 | } 24 | 25 | public void setCategory(CategoryDto category) { 26 | this.category = category; 27 | } 28 | 29 | public String getShortName() { 30 | return shortName; 31 | } 32 | 33 | public void setShortName(String shortName) { 34 | this.shortName = shortName; 35 | } 36 | 37 | public int getId() { 38 | return id; 39 | } 40 | 41 | public void setId(int id) { 42 | this.id = id; 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | public String getNick() { 54 | return nick; 55 | } 56 | 57 | public void setNick(String nick) { 58 | this.nick = nick; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/dto/CategoryDto.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.dto; 2 | 3 | public class CategoryDto { 4 | 5 | private String name; 6 | 7 | private String shortName; 8 | 9 | private int id; 10 | 11 | public String getShortName() { 12 | return shortName; 13 | } 14 | 15 | public void setShortName(String shortName) { 16 | this.shortName = shortName; 17 | } 18 | 19 | public int getId() { 20 | return id; 21 | } 22 | 23 | public void setId(int id) { 24 | this.id = id; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/dto/ItemDto.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.dto; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class ItemDto { 7 | 8 | private int id; 9 | 10 | private boolean enabled; 11 | 12 | private String title; 13 | 14 | private String description; 15 | 16 | private String link; 17 | 18 | private Date savedDate; 19 | 20 | private BlogDto blog; 21 | 22 | private int clickCount; 23 | 24 | private int likeCount; 25 | 26 | private int dislikeCount; 27 | 28 | private int twitterRetweetCount; 29 | 30 | private int facebookShareCount; 31 | 32 | private int linkedinShareCount; 33 | 34 | private int displayLikeCount; 35 | 36 | public String getSavedDateString() { 37 | return new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").format(savedDate); 38 | } 39 | 40 | public void setDisplayLikeCount(int displayLikeCount) { 41 | this.displayLikeCount = displayLikeCount; 42 | } 43 | 44 | public int getDisplayLikeCount() { 45 | return displayLikeCount; 46 | } 47 | 48 | public int getTwitterRetweetCount() { 49 | return twitterRetweetCount; 50 | } 51 | 52 | public void setTwitterRetweetCount(int twitterRetweetCount) { 53 | this.twitterRetweetCount = twitterRetweetCount; 54 | } 55 | 56 | public int getFacebookShareCount() { 57 | return facebookShareCount; 58 | } 59 | 60 | public void setFacebookShareCount(int facebookShareCount) { 61 | this.facebookShareCount = facebookShareCount; 62 | } 63 | 64 | public int getLinkedinShareCount() { 65 | return linkedinShareCount; 66 | } 67 | 68 | public void setLinkedinShareCount(int linkedinShareCount) { 69 | this.linkedinShareCount = linkedinShareCount; 70 | } 71 | 72 | public int getLikeCount() { 73 | return likeCount; 74 | } 75 | 76 | public void setLikeCount(int likeCount) { 77 | this.likeCount = likeCount; 78 | } 79 | 80 | public int getDislikeCount() { 81 | return dislikeCount; 82 | } 83 | 84 | public void setDislikeCount(int dislikeCount) { 85 | this.dislikeCount = dislikeCount; 86 | } 87 | 88 | public void setClickCount(int clickCount) { 89 | this.clickCount = clickCount; 90 | } 91 | 92 | public int getClickCount() { 93 | return clickCount; 94 | } 95 | 96 | public int getId() { 97 | return id; 98 | } 99 | 100 | public void setId(int id) { 101 | this.id = id; 102 | } 103 | 104 | public boolean isEnabled() { 105 | return enabled; 106 | } 107 | 108 | public void setEnabled(boolean enabled) { 109 | this.enabled = enabled; 110 | } 111 | 112 | public String getTitle() { 113 | return title; 114 | } 115 | 116 | public void setTitle(String title) { 117 | this.title = title; 118 | } 119 | 120 | public String getDescription() { 121 | return description; 122 | } 123 | 124 | public void setDescription(String description) { 125 | this.description = description; 126 | } 127 | 128 | public String getLink() { 129 | return link; 130 | } 131 | 132 | public void setLink(String link) { 133 | this.link = link; 134 | } 135 | 136 | public Date getSavedDate() { 137 | return savedDate; 138 | } 139 | 140 | public void setSavedDate(Date savedDate) { 141 | this.savedDate = savedDate; 142 | } 143 | 144 | public BlogDto getBlog() { 145 | return blog; 146 | } 147 | 148 | public void setBlog(BlogDto blog) { 149 | this.blog = blog; 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/Blog.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import javax.persistence.CascadeType; 7 | import javax.persistence.Column; 8 | import javax.persistence.Entity; 9 | import javax.persistence.FetchType; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.Id; 12 | import javax.persistence.JoinColumn; 13 | import javax.persistence.Lob; 14 | import javax.persistence.ManyToOne; 15 | import javax.persistence.OneToMany; 16 | import javax.validation.constraints.NotNull; 17 | import javax.validation.constraints.Size; 18 | 19 | import org.hibernate.validator.constraints.URL; 20 | 21 | import cz.jiripinkas.jba.annotation.UniqueBlog; 22 | import cz.jiripinkas.jba.annotation.UniqueShortName; 23 | import cz.jiripinkas.jba.util.MyUtil; 24 | 25 | @Entity 26 | public class Blog { 27 | 28 | @Id 29 | @GeneratedValue 30 | private Integer id; 31 | 32 | @Lob 33 | @Column(length = Integer.MAX_VALUE, updatable = false) 34 | private byte[] icon; 35 | 36 | @UniqueBlog(message = "This blog already exists!") 37 | @Size(min = 1, message = "Invalid URL!") 38 | @URL(message = "Invalid URL!") 39 | @Column(length = 1000, unique = true) 40 | private String url; 41 | 42 | @Size(min = 1, message = "Name must be at least 1 character!") 43 | private String name; 44 | 45 | @ManyToOne(fetch = FetchType.LAZY) 46 | @JoinColumn(name = "user_id") 47 | private User user; 48 | 49 | @OneToMany(mappedBy = "blog", cascade = CascadeType.REMOVE) 50 | private List items; 51 | 52 | @UniqueShortName(message = "This short name already exists!") 53 | @NotNull 54 | @Size(min = 1, message = "Short name cannot be empty!") 55 | @Column(name = "short_name", unique = true) 56 | private String shortName; 57 | 58 | private String nick; 59 | 60 | @NotNull 61 | @Size(min = 1, message = "Homepage cannot be empty!") 62 | @URL(message = "Invalid URL!") 63 | @Column(name = "homepage") 64 | private String homepageUrl; 65 | 66 | @Column(name = "last_check_status", updatable = false) 67 | private Boolean lastCheckStatus; 68 | 69 | /** 70 | * Date when was some item added. 71 | */ 72 | @Column(name = "last_indexed_date", updatable = false) 73 | private Date lastIndexedDate; 74 | 75 | @Lob 76 | @Column(name = "last_check_error_text", length = Integer.MAX_VALUE, updatable = false) 77 | private String lastCheckErrorText; 78 | 79 | @Column(name = "last_check_error_count", updatable = false) 80 | private Integer lastCheckErrorCount; 81 | 82 | @ManyToOne(fetch = FetchType.LAZY) 83 | @JoinColumn(name = "category_id") 84 | private Category category; 85 | 86 | private Boolean aggregator; 87 | 88 | @Column(name = "min_reddit_ups") 89 | private Integer minRedditUps; 90 | 91 | @Column(updatable = false) 92 | private Integer popularity; 93 | 94 | private Boolean archived; 95 | 96 | public Boolean getArchived() { 97 | return archived; 98 | } 99 | 100 | public void setArchived(Boolean archived) { 101 | this.archived = archived; 102 | } 103 | 104 | public Integer getMinRedditUps() { 105 | return minRedditUps; 106 | } 107 | 108 | public void setMinRedditUps(Integer minRedditUps) { 109 | this.minRedditUps = minRedditUps; 110 | } 111 | 112 | public Integer getPopularity() { 113 | return popularity; 114 | } 115 | 116 | public void setPopularity(Integer popularity) { 117 | this.popularity = popularity; 118 | } 119 | 120 | public String getPublicName() { 121 | return MyUtil.getPublicName(nick, name, false); 122 | } 123 | 124 | public void setAggregator(Boolean aggregator) { 125 | this.aggregator = aggregator; 126 | } 127 | 128 | public Boolean getAggregator() { 129 | return aggregator; 130 | } 131 | 132 | public void setCategory(Category category) { 133 | this.category = category; 134 | } 135 | 136 | public Category getCategory() { 137 | return category; 138 | } 139 | 140 | public String getLastCheckErrorText() { 141 | return lastCheckErrorText; 142 | } 143 | 144 | public void setLastCheckErrorText(String lastCheckErrorText) { 145 | this.lastCheckErrorText = lastCheckErrorText; 146 | } 147 | 148 | public Integer getLastCheckErrorCount() { 149 | return lastCheckErrorCount; 150 | } 151 | 152 | public void setLastCheckErrorCount(Integer lastCheckErrorCount) { 153 | this.lastCheckErrorCount = lastCheckErrorCount; 154 | } 155 | 156 | public Boolean getLastCheckStatus() { 157 | return lastCheckStatus; 158 | } 159 | 160 | public void setLastCheckStatus(Boolean lastCheckStatus) { 161 | this.lastCheckStatus = lastCheckStatus; 162 | } 163 | 164 | public String getShortName() { 165 | return shortName; 166 | } 167 | 168 | public void setShortName(String shortName) { 169 | this.shortName = shortName; 170 | } 171 | 172 | public String getHomepageUrl() { 173 | return homepageUrl; 174 | } 175 | 176 | public void setHomepageUrl(String homepageUrl) { 177 | this.homepageUrl = homepageUrl; 178 | } 179 | 180 | public byte[] getIcon() { 181 | return icon; 182 | } 183 | 184 | public void setIcon(byte[] icon) { 185 | this.icon = icon; 186 | } 187 | 188 | public User getUser() { 189 | return user; 190 | } 191 | 192 | public void setUser(User user) { 193 | this.user = user; 194 | } 195 | 196 | public List getItems() { 197 | return items; 198 | } 199 | 200 | public void setItems(List items) { 201 | this.items = items; 202 | } 203 | 204 | public Integer getId() { 205 | return id; 206 | } 207 | 208 | public void setId(Integer id) { 209 | this.id = id; 210 | } 211 | 212 | public String getUrl() { 213 | return url; 214 | } 215 | 216 | public void setUrl(String url) { 217 | this.url = url; 218 | } 219 | 220 | public String getName() { 221 | return name; 222 | } 223 | 224 | public void setName(String name) { 225 | this.name = name; 226 | } 227 | 228 | public String getNick() { 229 | return nick; 230 | } 231 | 232 | public void setNick(String nick) { 233 | this.nick = nick; 234 | } 235 | 236 | public Date getLastIndexedDate() { 237 | return lastIndexedDate; 238 | } 239 | 240 | public void setLastIndexedDate(Date lastIndexedDate) { 241 | this.lastIndexedDate = lastIndexedDate; 242 | } 243 | 244 | } 245 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/Category.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.Id; 9 | import javax.persistence.OneToMany; 10 | import javax.persistence.Transient; 11 | 12 | @Entity 13 | public class Category { 14 | 15 | @Id 16 | @GeneratedValue 17 | private int id; 18 | 19 | private String name; 20 | 21 | @Column(name = "short_name") 22 | private String shortName; 23 | 24 | @OneToMany(mappedBy = "category") 25 | private List blogs; 26 | 27 | @Transient 28 | private int blogCount; 29 | 30 | public int getBlogCount() { 31 | return blogCount; 32 | } 33 | 34 | public void setBlogCount(int blogCount) { 35 | this.blogCount = blogCount; 36 | } 37 | 38 | public String getShortName() { 39 | return shortName; 40 | } 41 | 42 | public void setShortName(String shortName) { 43 | this.shortName = shortName; 44 | } 45 | 46 | public void setBlogs(List blogs) { 47 | this.blogs = blogs; 48 | } 49 | 50 | public List getBlogs() { 51 | return blogs; 52 | } 53 | 54 | public int getId() { 55 | return id; 56 | } 57 | 58 | public void setId(int id) { 59 | this.id = id; 60 | } 61 | 62 | public String getName() { 63 | return name; 64 | } 65 | 66 | public void setName(String name) { 67 | this.name = name; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/Configuration.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.Lob; 8 | 9 | @Entity 10 | public class Configuration { 11 | 12 | @Id 13 | @GeneratedValue 14 | private int id; 15 | 16 | private String title; 17 | 18 | @Column(name = "brand_name") 19 | private String brandName; 20 | 21 | @Column(length = Integer.MAX_VALUE) 22 | @Lob 23 | private String footer; 24 | 25 | @Column(name = "google_adsense", length = Integer.MAX_VALUE) 26 | @Lob 27 | private String googleAdsense; 28 | 29 | @Column(name = "google_analytics", length = Integer.MAX_VALUE) 30 | @Lob 31 | private String googleAnalytics; 32 | 33 | @Column(name = "homepage_heading") 34 | private String homepageHeading; 35 | 36 | @Column(name = "top_heading") 37 | private String topHeading; 38 | 39 | @Column(name = "channel_title") 40 | private String channelTitle; 41 | 42 | @Column(name = "channel_link") 43 | private String channelLink; 44 | 45 | @Column(name = "channel_description") 46 | private String channelDescription; 47 | 48 | @Lob 49 | @Column(name = "news_social_buttons", length = Integer.MAX_VALUE) 50 | private String newsSocialButtons; 51 | 52 | @Lob 53 | @Column(name = "disqus_code", length = Integer.MAX_VALUE) 54 | private String disqusCode; 55 | 56 | @Lob 57 | @Column(name = "twitter_oauth", length = Integer.MAX_VALUE) 58 | private String twitterOauth; 59 | 60 | @Lob 61 | @Column(length = Integer.MAX_VALUE, updatable = false) 62 | private byte[] icon; 63 | 64 | @Lob 65 | @Column(length = Integer.MAX_VALUE, updatable = false) 66 | private byte[] favicon; 67 | 68 | @Lob 69 | @Column(length = Integer.MAX_VALUE, name = "apple_touch_icon", updatable = false) 70 | private byte[] appleTouchIcon; 71 | 72 | public byte[] getFavicon() { 73 | return favicon; 74 | } 75 | 76 | public void setFavicon(byte[] favicon) { 77 | this.favicon = favicon; 78 | } 79 | 80 | public byte[] getAppleTouchIcon() { 81 | return appleTouchIcon; 82 | } 83 | 84 | public void setAppleTouchIcon(byte[] appleTouchIcon) { 85 | this.appleTouchIcon = appleTouchIcon; 86 | } 87 | 88 | public void setDisqusCode(String disqusCode) { 89 | this.disqusCode = disqusCode; 90 | } 91 | 92 | public String getDisqusCode() { 93 | return disqusCode; 94 | } 95 | 96 | public String getNewsSocialButtons() { 97 | return newsSocialButtons; 98 | } 99 | 100 | public void setNewsSocialButtons(String newsSocialButtons) { 101 | this.newsSocialButtons = newsSocialButtons; 102 | } 103 | 104 | public String getChannelTitle() { 105 | return channelTitle; 106 | } 107 | 108 | public void setChannelTitle(String channelTitle) { 109 | this.channelTitle = channelTitle; 110 | } 111 | 112 | public String getChannelLink() { 113 | return channelLink; 114 | } 115 | 116 | public void setChannelLink(String channelLink) { 117 | this.channelLink = channelLink; 118 | } 119 | 120 | public String getChannelDescription() { 121 | return channelDescription; 122 | } 123 | 124 | public void setChannelDescription(String channelDescription) { 125 | this.channelDescription = channelDescription; 126 | } 127 | 128 | public void setIcon(byte[] icon) { 129 | this.icon = icon; 130 | } 131 | 132 | public byte[] getIcon() { 133 | return icon; 134 | } 135 | 136 | public void setHomepageHeading(String homepageHeading) { 137 | this.homepageHeading = homepageHeading; 138 | } 139 | 140 | public String getHomepageHeading() { 141 | return homepageHeading; 142 | } 143 | 144 | public void setTopHeading(String topHeading) { 145 | this.topHeading = topHeading; 146 | } 147 | 148 | public String getTopHeading() { 149 | return topHeading; 150 | } 151 | 152 | public int getId() { 153 | return id; 154 | } 155 | 156 | public void setId(int id) { 157 | this.id = id; 158 | } 159 | 160 | public String getTitle() { 161 | return title; 162 | } 163 | 164 | public void setTitle(String title) { 165 | this.title = title; 166 | } 167 | 168 | public String getBrandName() { 169 | return brandName; 170 | } 171 | 172 | public void setBrandName(String brandName) { 173 | this.brandName = brandName; 174 | } 175 | 176 | public String getFooter() { 177 | return footer; 178 | } 179 | 180 | public void setFooter(String footer) { 181 | this.footer = footer; 182 | } 183 | 184 | public String getGoogleAdsense() { 185 | return googleAdsense; 186 | } 187 | 188 | public void setGoogleAdsense(String googleAdsense) { 189 | this.googleAdsense = googleAdsense; 190 | } 191 | 192 | public String getGoogleAnalytics() { 193 | return googleAnalytics; 194 | } 195 | 196 | public void setGoogleAnalytics(String googleAnalytics) { 197 | this.googleAnalytics = googleAnalytics; 198 | } 199 | 200 | public String getTwitterOauth() { 201 | return twitterOauth; 202 | } 203 | 204 | public void setTwitterOauth(String twitterOauth) { 205 | this.twitterOauth = twitterOauth; 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/Item.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import java.util.Date; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Entity; 7 | import javax.persistence.FetchType; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.Id; 10 | import javax.persistence.JoinColumn; 11 | import javax.persistence.Lob; 12 | import javax.persistence.ManyToOne; 13 | import javax.persistence.Transient; 14 | 15 | import org.hibernate.annotations.Type; 16 | 17 | @Entity 18 | public class Item { 19 | 20 | @Id 21 | @GeneratedValue 22 | private Integer id; 23 | 24 | @Column(length = 1000) 25 | private String title; 26 | 27 | @Lob 28 | @Type(type = "org.hibernate.type.TextType") 29 | @Column(length = Integer.MAX_VALUE) 30 | private String description; 31 | 32 | /** 33 | * When was the item published by it's owner 34 | */ 35 | @Column(name = "published_date") 36 | private Date publishedDate; 37 | 38 | @Column(length = 1000) 39 | private String link; 40 | 41 | @ManyToOne(fetch = FetchType.LAZY) 42 | @JoinColumn(name = "blog_id") 43 | private Blog blog; 44 | 45 | private boolean enabled; 46 | 47 | @Column(name = "click_count", nullable = false) 48 | private Integer clickCount; 49 | 50 | @Column(name = "like_count", nullable = false) 51 | private Integer likeCount; 52 | 53 | @Column(name = "dislike_count", nullable = false) 54 | private Integer dislikeCount; 55 | 56 | @Column(name = "twitter_retweet_count", nullable = false) 57 | private Integer twitterRetweetCount; 58 | 59 | @Column(name = "facebook_share_count", nullable = false) 60 | private Integer facebookShareCount; 61 | 62 | @Column(name = "linkedin_share_count", nullable = false) 63 | private Integer linkedinShareCount; 64 | 65 | /** 66 | * When was the item saved to local database 67 | */ 68 | @Column(name = "saved_date") 69 | private Date savedDate; 70 | 71 | @Transient 72 | private String error; 73 | 74 | public Item() { 75 | setEnabled(true); 76 | setClickCount(0); 77 | setLikeCount(0); 78 | setDislikeCount(0); 79 | setTwitterRetweetCount(0); 80 | setFacebookShareCount(0); 81 | setLinkedinShareCount(0); 82 | } 83 | 84 | public Integer getTwitterRetweetCount() { 85 | return twitterRetweetCount; 86 | } 87 | 88 | public void setTwitterRetweetCount(Integer twitterRetweetCount) { 89 | this.twitterRetweetCount = twitterRetweetCount; 90 | } 91 | 92 | public Integer getFacebookShareCount() { 93 | return facebookShareCount; 94 | } 95 | 96 | public void setFacebookShareCount(Integer facebookShareCount) { 97 | this.facebookShareCount = facebookShareCount; 98 | } 99 | 100 | public Integer getLinkedinShareCount() { 101 | return linkedinShareCount; 102 | } 103 | 104 | public void setLinkedinShareCount(Integer linkedinShareCount) { 105 | this.linkedinShareCount = linkedinShareCount; 106 | } 107 | 108 | public String getError() { 109 | return error; 110 | } 111 | 112 | public void setError(String error) { 113 | this.error = error; 114 | } 115 | 116 | public Integer getLikeCount() { 117 | return likeCount; 118 | } 119 | 120 | public void setLikeCount(Integer likeCount) { 121 | this.likeCount = likeCount; 122 | } 123 | 124 | public Integer getDislikeCount() { 125 | return dislikeCount; 126 | } 127 | 128 | public void setDislikeCount(Integer dislikeCount) { 129 | this.dislikeCount = dislikeCount; 130 | } 131 | 132 | public void setClickCount(Integer clickCount) { 133 | this.clickCount = clickCount; 134 | } 135 | 136 | public Integer getClickCount() { 137 | return clickCount; 138 | } 139 | 140 | public boolean isEnabled() { 141 | return enabled; 142 | } 143 | 144 | public void setEnabled(boolean enabled) { 145 | this.enabled = enabled; 146 | } 147 | 148 | public Blog getBlog() { 149 | return blog; 150 | } 151 | 152 | public void setBlog(Blog blog) { 153 | this.blog = blog; 154 | } 155 | 156 | public Integer getId() { 157 | return id; 158 | } 159 | 160 | public void setId(Integer id) { 161 | this.id = id; 162 | } 163 | 164 | public String getTitle() { 165 | return title; 166 | } 167 | 168 | public void setTitle(String title) { 169 | this.title = title; 170 | } 171 | 172 | public String getDescription() { 173 | return description; 174 | } 175 | 176 | public void setDescription(String description) { 177 | this.description = description; 178 | } 179 | 180 | public Date getPublishedDate() { 181 | return publishedDate; 182 | } 183 | 184 | public void setPublishedDate(Date publishedDate) { 185 | this.publishedDate = publishedDate; 186 | } 187 | 188 | public String getLink() { 189 | return link; 190 | } 191 | 192 | public void setLink(String link) { 193 | this.link = link; 194 | } 195 | 196 | public Date getSavedDate() { 197 | return savedDate; 198 | } 199 | 200 | public void setSavedDate(Date savedDate) { 201 | this.savedDate = savedDate; 202 | } 203 | 204 | } 205 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/NewsItem.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | import javax.persistence.Column; 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.Id; 10 | import javax.persistence.Lob; 11 | import javax.persistence.Table; 12 | 13 | @Entity 14 | @Table(name = "news_item") 15 | public class NewsItem { 16 | 17 | @Id 18 | @GeneratedValue 19 | private Integer id; 20 | 21 | @Column(length = 500) 22 | private String title; 23 | 24 | @Column(name = "short_description", length = 500) 25 | private String shortDescription; 26 | 27 | @Column(length = Integer.MAX_VALUE) 28 | @Lob 29 | private String description; 30 | 31 | @Column(name = "published_date") 32 | private Date publishedDate; 33 | 34 | @Column(name = "short_name", length = 500, unique = true) 35 | private String shortName; 36 | 37 | public String getFormattedPuslihedDate() { 38 | return new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(publishedDate); 39 | } 40 | 41 | public String getShortDescription() { 42 | return shortDescription; 43 | } 44 | 45 | public void setShortDescription(String shortDescription) { 46 | this.shortDescription = shortDescription; 47 | } 48 | 49 | public String getShortName() { 50 | return shortName; 51 | } 52 | 53 | public void setShortName(String shortName) { 54 | this.shortName = shortName; 55 | } 56 | 57 | public Integer getId() { 58 | return id; 59 | } 60 | 61 | public void setId(Integer id) { 62 | this.id = id; 63 | } 64 | 65 | public String getTitle() { 66 | return title; 67 | } 68 | 69 | public void setTitle(String title) { 70 | this.title = title; 71 | } 72 | 73 | public String getDescription() { 74 | return description; 75 | } 76 | 77 | public void setDescription(String description) { 78 | this.description = description; 79 | } 80 | 81 | public Date getPublishedDate() { 82 | return publishedDate; 83 | } 84 | 85 | public void setPublishedDate(Date publishedDate) { 86 | this.publishedDate = publishedDate; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/Role.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.ManyToMany; 9 | 10 | @Entity 11 | public class Role { 12 | 13 | @Id 14 | @GeneratedValue 15 | private Integer id; 16 | 17 | private String name; 18 | 19 | @ManyToMany(mappedBy = "roles") 20 | private List users; 21 | 22 | public List getUsers() { 23 | return users; 24 | } 25 | 26 | public void setUsers(List users) { 27 | this.users = users; 28 | } 29 | 30 | public Integer getId() { 31 | return id; 32 | } 33 | 34 | public void setId(Integer id) { 35 | this.id = id; 36 | } 37 | 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | public void setName(String name) { 43 | this.name = name; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/entity/User.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.entity; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.CascadeType; 6 | import javax.persistence.Column; 7 | import javax.persistence.Entity; 8 | import javax.persistence.GeneratedValue; 9 | import javax.persistence.Id; 10 | import javax.persistence.JoinTable; 11 | import javax.persistence.ManyToMany; 12 | import javax.persistence.OneToMany; 13 | import javax.persistence.Table; 14 | import javax.validation.constraints.Email; 15 | import javax.validation.constraints.Size; 16 | 17 | import cz.jiripinkas.jba.annotation.UniqueUsername; 18 | 19 | @Entity 20 | @Table(name = "app_user") 21 | public class User { 22 | 23 | @Id 24 | @GeneratedValue 25 | private Integer id; 26 | 27 | @Size(min = 3, message = "Name must be at least 3 characters!") 28 | @Column(unique = true) 29 | @UniqueUsername(message = "Such username already exists!") 30 | private String name; 31 | 32 | @Size(min = 1, message = "Invalid email address!") 33 | @Email(message = "Invalid email address!") 34 | private String email; 35 | 36 | @Size(min = 5, message = "Password must be at least 5 characters!") 37 | private String password; 38 | 39 | private boolean enabled; 40 | 41 | @ManyToMany 42 | @JoinTable(name="app_user_role") 43 | private List roles; 44 | 45 | @OneToMany(mappedBy = "user", cascade = CascadeType.REMOVE) 46 | private List blogs; 47 | 48 | private boolean admin; 49 | 50 | public boolean isAdmin() { 51 | return admin; 52 | } 53 | 54 | public void setAdmin(boolean admin) { 55 | this.admin = admin; 56 | } 57 | 58 | public boolean isEnabled() { 59 | return enabled; 60 | } 61 | 62 | public void setEnabled(boolean enabled) { 63 | this.enabled = enabled; 64 | } 65 | 66 | public List getBlogs() { 67 | return blogs; 68 | } 69 | 70 | public void setBlogs(List blogs) { 71 | this.blogs = blogs; 72 | } 73 | 74 | public List getRoles() { 75 | return roles; 76 | } 77 | 78 | public void setRoles(List roles) { 79 | this.roles = roles; 80 | } 81 | 82 | public Integer getId() { 83 | return id; 84 | } 85 | 86 | public void setId(Integer id) { 87 | this.id = id; 88 | } 89 | 90 | public String getName() { 91 | return name; 92 | } 93 | 94 | public void setName(String name) { 95 | this.name = name; 96 | } 97 | 98 | public String getEmail() { 99 | return email; 100 | } 101 | 102 | public void setEmail(String email) { 103 | this.email = email; 104 | } 105 | 106 | public String getPassword() { 107 | return password; 108 | } 109 | 110 | public void setPassword(String password) { 111 | this.password = password; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/exception/PageNotFoundException.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.exception; 2 | 3 | public class PageNotFoundException extends RuntimeException { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/exception/RssException.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.exception; 2 | 3 | public class RssException extends Exception { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public RssException(Throwable cause) { 8 | super(cause); 9 | } 10 | 11 | public RssException(String message) { 12 | super(message); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/exception/UrlException.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.exception; 2 | 3 | public class UrlException extends Exception { 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public UrlException(String message) { 8 | super(message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/BlogRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import java.util.List; 4 | 5 | import javax.transaction.Transactional; 6 | 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Modifying; 9 | import org.springframework.data.jpa.repository.Query; 10 | 11 | import cz.jiripinkas.jba.entity.Blog; 12 | 13 | public interface BlogRepository extends JpaRepository { 14 | 15 | @Query("select distinct b from Blog b left join fetch b.items where b.user.id = ?1 order by b.id") 16 | List findByUserId(int id); 17 | 18 | Blog findByUrl(String url); 19 | 20 | @Query("select b from Blog b join fetch b.user where b.id = ?1") 21 | Blog findOneFetchUser(int id); 22 | 23 | @Query("select b from Blog b left join fetch b.category where b.shortName = ?1") 24 | Blog findByShortName(String shortName); 25 | 26 | @Query("select b from Blog b join fetch b.user left join fetch b.category order by b.shortName") 27 | List findAllFetchUser(); 28 | 29 | @Query("select b from Blog b join fetch b.user join fetch b.category order by b.shortName") 30 | List findAllWithCategoryFetchUser(); 31 | 32 | Blog findByIdAndUserName(int id, String username); 33 | 34 | @Modifying 35 | @Query("update Blog b set b.lastCheckErrorText = null, b.lastCheckErrorCount = 0, b.lastCheckStatus = true where b.id = ?1") 36 | void saveOk(int blogId); 37 | 38 | @Modifying 39 | @Query("update Blog b set b.lastCheckErrorText = ?3, b.lastCheckErrorCount = ?2, b.lastCheckStatus = false where b.id = ?1") 40 | void saveFail(int blogId, int errorCount, String errorText); 41 | 42 | int countByCategoryId(int categoryId); 43 | 44 | @Modifying 45 | @Query("update Blog b set b.lastIndexedDate = current_timestamp where b.id = ?1") 46 | void saveLastIndexedDate(int blogId); 47 | 48 | @Modifying 49 | @Query("update Blog b set b.popularity = ?2 where b.id = ?1") 50 | void setPopularity(int blogId, int popularity); 51 | 52 | @Query("select count(b) from Blog b where b.category is null") 53 | long countUnapproved(); 54 | 55 | @Transactional 56 | @Modifying 57 | @Query("update Blog b set b.icon = ?2 where b.id = ?1") 58 | void saveIcon(int blogId, byte[] icon); 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/CategoryRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import cz.jiripinkas.jba.entity.Category; 6 | 7 | public interface CategoryRepository extends JpaRepository { 8 | 9 | Category findByShortName(String shortName); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/ConfigurationRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import javax.transaction.Transactional; 4 | 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Modifying; 7 | import org.springframework.data.jpa.repository.Query; 8 | 9 | import cz.jiripinkas.jba.entity.Configuration; 10 | 11 | public interface ConfigurationRepository extends JpaRepository { 12 | 13 | @Transactional 14 | @Modifying 15 | @Query("update Configuration c set c.icon = ?1") 16 | void saveIcon(byte[] icon); 17 | 18 | @Transactional 19 | @Modifying 20 | @Query("update Configuration c set c.favicon = ?1") 21 | void saveFavicon(byte[] icon); 22 | 23 | @Transactional 24 | @Modifying 25 | @Query("update Configuration c set c.appleTouchIcon = ?1") 26 | void saveAppleTouchIcon(byte[] icon); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/ItemRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.data.jpa.repository.Modifying; 9 | import org.springframework.data.jpa.repository.Query; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import cz.jiripinkas.jba.entity.Item; 13 | 14 | public interface ItemRepository extends JpaRepository { 15 | 16 | @Query("select i.id from Item i where i.link = ?1 and i.blog.id = ?2") 17 | Integer findItemIdByLinkAndBlogId(String link, int blogId); 18 | 19 | @Query("select i from Item i join fetch i.blog b left join fetch b.category cat where i.enabled = true and cat.shortName = ?1") 20 | List findCategoryPageEnabled(String shortName, Pageable pageable); 21 | 22 | @Transactional 23 | @Modifying 24 | @Query("update Item i set i.likeCount = i.likeCount + ?2 where i.id = ?1") 25 | void changeLike(int id, int amount); 26 | 27 | @Transactional 28 | @Modifying 29 | @Query("update Item i set i.dislikeCount = i.dislikeCount + ?2 where i.id = ?1") 30 | void changeDislike(int id, int amount); 31 | 32 | @Query("select i.dislikeCount from Item i where i.id = ?1") 33 | int getDislikeCount(int id); 34 | 35 | @Transactional 36 | @Modifying 37 | @Query("update Item i set i.clickCount = i.clickCount + 1 where i.id = ?1") 38 | void incClickCount(int id); 39 | 40 | @Query("select i.clickCount from Item i where i.id = ?1") 41 | int getClickCount(int id); 42 | 43 | @Query("select i.link from Item i") 44 | List findAllLinks(); 45 | 46 | @Query("select lower(i.title) from Item i") 47 | List findAllLowercaseTitles(); 48 | 49 | @Transactional 50 | @Modifying 51 | @Query("update Item i set i.twitterRetweetCount = ?2 where i.id = ?1") 52 | void setTwitterRetweetCount(int id, int count); 53 | 54 | @Transactional 55 | @Modifying 56 | @Query("update Item i set i.facebookShareCount = ?2 where i.id = ?1") 57 | void setFacebookShareCount(int id, int shares); 58 | 59 | @Transactional 60 | @Modifying 61 | @Query("update Item i set i.linkedinShareCount = ?2 where i.id = ?1") 62 | void setLinkedinShareCount(int id, int count); 63 | 64 | @Transactional 65 | @Modifying 66 | @Query("update Item i set i.savedDate = i.publishedDate where i.savedDate is null") 67 | void updateSavedDates(); 68 | 69 | @Query("select sum(coalesce(i.likeCount, 0) + ((log(coalesce(i.clickCount, 0) + 1) * 10) + (log(coalesce(i.twitterRetweetCount, 0) + 1) * 10) + (log(coalesce(i.facebookShareCount, 0) + 1) * 3) + (log(coalesce(i.linkedinShareCount, 0) + 1) * 10))) / coalesce(count(i), 1) from Item i where i.blog.id = ?1 and i.savedDate > ?2") 70 | Integer getSocialSum(int blogId, Date dateFrom); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/NewsItemRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import cz.jiripinkas.jba.entity.NewsItem; 6 | 7 | public interface NewsItemRepository extends JpaRepository { 8 | 9 | NewsItem findByShortName(String shortName); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/RoleRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import cz.jiripinkas.jba.entity.Role; 6 | 7 | public interface RoleRepository extends JpaRepository{ 8 | 9 | Role findByName(String name); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.repository; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Modifying; 7 | import org.springframework.data.jpa.repository.Query; 8 | 9 | import cz.jiripinkas.jba.entity.User; 10 | 11 | public interface UserRepository extends JpaRepository { 12 | 13 | User findByName(String name); 14 | 15 | @Query("select u from User u where u.admin = true") 16 | User findAdmin(); 17 | 18 | @Modifying 19 | @Query("update User u set u.password = ?1 where u.admin = true") 20 | void updateAdminPassword(String password); 21 | 22 | @Modifying 23 | @Query("update User u set u.name = ?1 where u.admin = true") 24 | void updateAdminName(String name); 25 | 26 | @Query("select distinct u from User u left join fetch u.roles") 27 | List findAllFetchRoles(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/rss/TRss.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.rss; 2 | 3 | import java.util.List; 4 | 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlElement; 8 | import javax.xml.bind.annotation.XmlRootElement; 9 | 10 | @XmlAccessorType(XmlAccessType.FIELD) 11 | @XmlRootElement(name = "rss") 12 | public class TRss { 13 | 14 | @XmlElement(name = "channel") 15 | List channels; 16 | 17 | public List getChannels() { 18 | return channels; 19 | } 20 | 21 | public void setChannels(List channels) { 22 | this.channels = channels; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/rss/TRssChannel.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.rss; 2 | 3 | import java.util.List; 4 | 5 | import javax.xml.bind.annotation.XmlAccessType; 6 | import javax.xml.bind.annotation.XmlAccessorType; 7 | import javax.xml.bind.annotation.XmlElement; 8 | 9 | @XmlAccessorType(XmlAccessType.FIELD) 10 | public class TRssChannel { 11 | 12 | private String title; 13 | 14 | private String link; 15 | 16 | private String description; 17 | 18 | private String lastBuildDate; 19 | 20 | @XmlElement(name = "item") 21 | List items; 22 | 23 | public List getItems() { 24 | return items; 25 | } 26 | 27 | public void setItems(List items) { 28 | this.items = items; 29 | } 30 | 31 | public String getTitle() { 32 | return title; 33 | } 34 | 35 | public void setTitle(String title) { 36 | this.title = title; 37 | } 38 | 39 | public String getLink() { 40 | return link; 41 | } 42 | 43 | public void setLink(String link) { 44 | this.link = link; 45 | } 46 | 47 | public String getDescription() { 48 | return description; 49 | } 50 | 51 | public void setDescription(String description) { 52 | this.description = description; 53 | } 54 | 55 | public String getLastBuildDate() { 56 | return lastBuildDate; 57 | } 58 | 59 | public void setLastBuildDate(String lastBuildDate) { 60 | this.lastBuildDate = lastBuildDate; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/rss/TRssItem.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.rss; 2 | 3 | import javax.xml.bind.annotation.XmlAccessType; 4 | import javax.xml.bind.annotation.XmlAccessorType; 5 | import javax.xml.bind.annotation.XmlElement; 6 | 7 | @XmlAccessorType(XmlAccessType.FIELD) 8 | public class TRssItem { 9 | 10 | private String title; 11 | 12 | private String description; 13 | 14 | private String pubDate; 15 | 16 | private String link; 17 | 18 | @XmlElement(namespace = "http://rssnamespace.org/feedburner/ext/1.0") 19 | private String origLink; 20 | 21 | @XmlElement(namespace = "http://purl.org/rss/1.0/modules/content/") 22 | private String encoded; 23 | 24 | public String getEncoded() { 25 | return encoded; 26 | } 27 | 28 | public void setEncoded(String encoded) { 29 | this.encoded = encoded; 30 | } 31 | 32 | public String getOrigLink() { 33 | return origLink; 34 | } 35 | 36 | public void setOrigLink(String origLink) { 37 | this.origLink = origLink; 38 | } 39 | 40 | public String getPubDate() { 41 | return pubDate; 42 | } 43 | 44 | public void setPubDate(String pubDate) { 45 | this.pubDate = pubDate; 46 | } 47 | 48 | public void setLink(String link) { 49 | this.link = link; 50 | } 51 | 52 | public String getLink() { 53 | return link; 54 | } 55 | 56 | public String getDescription() { 57 | return description; 58 | } 59 | 60 | public void setDescription(String description) { 61 | this.description = description; 62 | } 63 | 64 | public String getTitle() { 65 | return title; 66 | } 67 | 68 | public void setTitle(String title) { 69 | this.title = title; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/rss/package-info.java: -------------------------------------------------------------------------------- 1 | @XmlSchema(namespace = "", elementFormDefault = XmlNsForm.QUALIFIED, xmlns = { @XmlNs(prefix = "feedburner", namespaceURI = "http://rssnamespace.org/feedburner/ext/1.0"), 2 | @XmlNs(prefix = "content", namespaceURI = "http://purl.org/rss/1.0/modules/content/") }) 3 | package cz.jiripinkas.jba.rss; 4 | 5 | import javax.xml.bind.annotation.XmlNs; 6 | import javax.xml.bind.annotation.XmlNsForm; 7 | import javax.xml.bind.annotation.XmlSchema; 8 | 9 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/AllCategoriesService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import cz.jiripinkas.jba.entity.Category; 9 | 10 | @Service 11 | public class AllCategoriesService { 12 | 13 | @Autowired 14 | private CategoryService categoryService; 15 | 16 | public Integer[] getAllCategoryIds() { 17 | List categories = categoryService.findAll(); 18 | Integer[] result = new Integer[categories.size()]; 19 | for (int i = 0; i < categories.size(); i++) { 20 | result[i] = categories.get(i).getId(); 21 | } 22 | return result; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/BlogResultService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | import org.springframework.transaction.annotation.Propagation; 6 | import org.springframework.transaction.annotation.Transactional; 7 | 8 | import cz.jiripinkas.jba.entity.Blog; 9 | import cz.jiripinkas.jba.repository.BlogRepository; 10 | 11 | @Service 12 | public class BlogResultService { 13 | 14 | @Autowired 15 | private BlogRepository blogRepository; 16 | 17 | @Transactional(propagation = Propagation.REQUIRES_NEW) 18 | public void saveOk(Blog blog) { 19 | blogRepository.saveOk(blog.getId()); 20 | } 21 | 22 | @Transactional(propagation = Propagation.REQUIRES_NEW) 23 | public void saveLastIndexedDate(Blog blog) { 24 | blogRepository.saveLastIndexedDate(blog.getId()); 25 | } 26 | 27 | @Transactional(propagation = Propagation.REQUIRES_NEW) 28 | public void saveFail(Blog blog, String errorText) { 29 | int errorCount = 0; 30 | if (blog.getLastCheckErrorCount() != null) { 31 | errorCount = blog.getLastCheckErrorCount(); 32 | } 33 | errorCount++; 34 | blogRepository.saveFail(blog.getId(), errorCount, errorText); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/CategoryService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import cz.jiripinkas.jba.dto.CategoryDto; 4 | import cz.jiripinkas.jba.entity.Blog; 5 | import cz.jiripinkas.jba.entity.Category; 6 | import cz.jiripinkas.jba.repository.BlogRepository; 7 | import cz.jiripinkas.jba.repository.CategoryRepository; 8 | import ma.glasnost.orika.MapperFacade; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.cache.annotation.CacheEvict; 11 | import org.springframework.cache.annotation.Cacheable; 12 | import org.springframework.stereotype.Service; 13 | 14 | import java.util.List; 15 | 16 | @Service 17 | public class CategoryService { 18 | 19 | @Autowired 20 | private CategoryRepository categoryRepository; 21 | 22 | @Autowired 23 | private BlogRepository blogRepository; 24 | 25 | @Autowired 26 | private MapperFacade mapperFacade; 27 | 28 | @Cacheable("categories") 29 | public List findAll() { 30 | List categories = categoryRepository.findAll(); 31 | for (Category category : categories) { 32 | category.setBlogCount(blogRepository.countByCategoryId(category.getId())); 33 | } 34 | return categories; 35 | } 36 | 37 | @CacheEvict(value = "categories", allEntries = true) 38 | public void save(Category category) { 39 | categoryRepository.save(category); 40 | } 41 | 42 | @CacheEvict(value = "categories", allEntries = true) 43 | public void delete(int id) { 44 | categoryRepository.deleteById(id); 45 | } 46 | 47 | public CategoryDto findOneDto(int id) { 48 | return mapperFacade.map(categoryRepository.findById(id).get(), CategoryDto.class); 49 | } 50 | 51 | @CacheEvict(value = "blogCountUnapproved", allEntries = true) 52 | public void addMapping(int blogId, int categoryId) { 53 | Category category = categoryRepository.findById(categoryId).get(); 54 | Blog blog = blogRepository.findById(blogId).get(); 55 | blog.setCategory(category); 56 | blogRepository.save(blog); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/ConfigurationInterceptor.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.apache.commons.lang.RandomStringUtils; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.core.env.Environment; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.servlet.ModelAndView; 11 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 12 | 13 | @Component 14 | public class ConfigurationInterceptor extends HandlerInterceptorAdapter { 15 | 16 | @Autowired 17 | private ConfigurationService configurationService; 18 | 19 | @Autowired 20 | private CategoryService categoryService; 21 | 22 | @Autowired 23 | private BlogService blogService; 24 | 25 | @Autowired 26 | private UserService userService; 27 | 28 | @Autowired 29 | private ItemService itemService; 30 | 31 | @Autowired 32 | private Environment environment; 33 | 34 | @Override 35 | public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { 36 | /* 37 | * Attributes will be available in every page. 38 | */ 39 | if (modelAndView != null) { 40 | if(environment.acceptsProfiles("dev")) { 41 | modelAndView.getModelMap().addAttribute("isDevProfileActive", true); 42 | } else { 43 | modelAndView.getModelMap().addAttribute("isDevProfileActive", false); 44 | } 45 | String adBlockClass = RandomStringUtils.randomAlphabetic(30); 46 | modelAndView.getModelMap().addAttribute("adBlockMessageClass", adBlockClass); 47 | String adBlockCss = 48 | " \n"; 54 | modelAndView.getModelMap().addAttribute("adBlockCss", adBlockCss); 55 | modelAndView.getModelMap().addAttribute("configuration", configurationService.find()); 56 | modelAndView.getModelMap().addAttribute("categories", categoryService.findAll()); 57 | modelAndView.getModelMap().addAttribute("lastIndexDate", blogService.getLastIndexDateMinutes()); 58 | modelAndView.getModelMap().addAttribute("blogCount", blogService.count()); 59 | if (request.isUserInRole("ADMIN")) { 60 | modelAndView.getModelMap().addAttribute("itemCount", itemService.count()); 61 | modelAndView.getModelMap().addAttribute("userCount", userService.count()); 62 | modelAndView.getModelMap().addAttribute("blogCountUnapproved", blogService.countUnapproved()); 63 | } 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/ConfigurationService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.cache.annotation.CacheEvict; 7 | import org.springframework.cache.annotation.Cacheable; 8 | import org.springframework.stereotype.Service; 9 | 10 | import cz.jiripinkas.jba.entity.Configuration; 11 | import cz.jiripinkas.jba.repository.ConfigurationRepository; 12 | 13 | @Service 14 | public class ConfigurationService { 15 | 16 | @Autowired 17 | private ConfigurationRepository configurationRepository; 18 | 19 | @Cacheable("configuration") 20 | public Configuration find() { 21 | List configurations = configurationRepository.findAll(); 22 | if (configurations.size() == 0) { 23 | return null; 24 | } else if (configurations.size() > 1) { 25 | throw new UnsupportedOperationException("There can be only one configuration!"); 26 | } 27 | return configurations.get(0); 28 | } 29 | 30 | @CacheEvict(value = "configuration", allEntries = true) 31 | public void saveIcon(byte[] bytes) { 32 | configurationRepository.saveIcon(bytes); 33 | } 34 | 35 | @CacheEvict(value = "configuration", allEntries = true) 36 | public void saveFavicon(byte[] bytes) { 37 | configurationRepository.saveFavicon(bytes); 38 | } 39 | 40 | @CacheEvict(value = "configuration", allEntries = true) 41 | public void saveAppleTouchIcon(byte[] bytes) { 42 | configurationRepository.saveAppleTouchIcon(bytes); 43 | } 44 | 45 | @CacheEvict(value = "configuration", allEntries = true) 46 | public void save(Configuration newConfiguration) { 47 | Configuration managedConfiguration = find(); 48 | if (managedConfiguration != null) { 49 | newConfiguration.setId(managedConfiguration.getId()); 50 | } 51 | configurationRepository.save(newConfiguration); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/NewsService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.PageRequest; 9 | import org.springframework.data.domain.Sort.Direction; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.annotation.Transactional; 12 | 13 | import cz.jiripinkas.jba.entity.Configuration; 14 | import cz.jiripinkas.jba.entity.NewsItem; 15 | import cz.jiripinkas.jba.repository.NewsItemRepository; 16 | import cz.jiripinkas.jba.util.MyUtil; 17 | import cz.jiripinkas.jsitemapgenerator.RssItemBuilder; 18 | import cz.jiripinkas.jsitemapgenerator.generator.RssGenerator; 19 | 20 | @Service 21 | public class NewsService { 22 | 23 | private static final int PAGE_SIZE = 10; 24 | 25 | @Autowired 26 | private NewsItemRepository newsItemRepository; 27 | 28 | @Autowired 29 | private ConfigurationService configurationService; 30 | 31 | public void save(NewsItem newsItem) { 32 | newsItem.setPublishedDate(new Date()); 33 | if (newsItem.getShortName() == null || newsItem.getShortName().isEmpty()) { 34 | newsItem.setShortName(MyUtil.generatePermalink(newsItem.getTitle())); 35 | } 36 | newsItemRepository.save(newsItem); 37 | } 38 | 39 | public Page findNews(int page) { 40 | return newsItemRepository.findAll(PageRequest.of(page, PAGE_SIZE, Direction.DESC, "publishedDate")); 41 | } 42 | 43 | public List findAll() { 44 | return newsItemRepository.findAll(); 45 | } 46 | 47 | @Transactional 48 | public NewsItem findOne(String shortName) { 49 | return newsItemRepository.findByShortName(shortName); 50 | } 51 | 52 | public String getFeed() { 53 | Configuration configuration = configurationService.find(); 54 | Page firstTenNews = findNews(0); 55 | RssGenerator rssGenerator = new RssGenerator(configuration.getChannelLink(), configuration.getChannelTitle(), configuration.getChannelDescription()); 56 | for (NewsItem newsItem : firstTenNews.getContent()) { 57 | rssGenerator.addPage( 58 | new RssItemBuilder() 59 | .title(newsItem.getTitle()) 60 | .description(newsItem.getShortDescription()) 61 | .name("news/" + newsItem.getShortName()) 62 | .pubDate(newsItem.getPublishedDate()) 63 | .build() 64 | ); 65 | } 66 | return rssGenerator.constructRss(); 67 | } 68 | 69 | public void delete(int id) { 70 | newsItemRepository.deleteById(id); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/UserService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Optional; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.cache.annotation.CacheEvict; 9 | import org.springframework.cache.annotation.Cacheable; 10 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.transaction.annotation.Transactional; 13 | 14 | import cz.jiripinkas.jba.entity.Blog; 15 | import cz.jiripinkas.jba.entity.Role; 16 | import cz.jiripinkas.jba.entity.User; 17 | import cz.jiripinkas.jba.repository.BlogRepository; 18 | import cz.jiripinkas.jba.repository.RoleRepository; 19 | import cz.jiripinkas.jba.repository.UserRepository; 20 | 21 | @Service 22 | @Transactional 23 | public class UserService { 24 | 25 | @Autowired 26 | private UserRepository userRepository; 27 | 28 | @Autowired 29 | private RoleRepository roleRepository; 30 | 31 | @Autowired 32 | private BlogRepository blogRepository; 33 | 34 | public List findAll() { 35 | return userRepository.findAllFetchRoles(); 36 | } 37 | 38 | @Transactional 39 | public User findOneWithBlogs(int id) { 40 | User user = userRepository.findById(id).get(); 41 | List blogs = blogRepository.findByUserId(id); 42 | user.setBlogs(blogs); 43 | return user; 44 | } 45 | 46 | @CacheEvict(value = "userCount", allEntries = true) 47 | public void save(User user) { 48 | user.setEnabled(true); 49 | BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); 50 | user.setPassword(encoder.encode(user.getPassword())); 51 | 52 | List roles = new ArrayList<>(); 53 | roles.add(roleRepository.findByName("ROLE_USER")); 54 | user.setRoles(roles); 55 | 56 | userRepository.save(user); 57 | } 58 | 59 | /** 60 | * Called from admin-detail.html 61 | * 62 | * @param user 63 | */ 64 | public void saveAdmin(User user) { 65 | BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); 66 | String encodedPassword = encoder.encode(user.getPassword()); 67 | userRepository.updateAdminPassword(encodedPassword); 68 | userRepository.updateAdminName(user.getName()); 69 | } 70 | 71 | public User findOneWithBlogs(String name) { 72 | User user = userRepository.findByName(name); 73 | return findOneWithBlogs(user.getId()); 74 | } 75 | 76 | @CacheEvict(value = "userCount", allEntries = true) 77 | public void delete(int id) { 78 | userRepository.deleteById(id); 79 | } 80 | 81 | public User findOne(String username) { 82 | return userRepository.findByName(username); 83 | } 84 | 85 | @Cacheable("userCount") 86 | public long count() { 87 | return userRepository.count(); 88 | } 89 | 90 | public User findAdmin() { 91 | return userRepository.findAdmin(); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/service/initdb/HsqldbManagerService.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service.initdb; 2 | 3 | import javax.annotation.PostConstruct; 4 | 5 | import org.hsqldb.util.DatabaseManagerSwing; 6 | import org.springframework.stereotype.Service; 7 | 8 | import cz.jiripinkas.jba.annotation.DevProfile; 9 | 10 | @DevProfile 11 | @Service 12 | public class HsqldbManagerService { 13 | 14 | @PostConstruct 15 | public void getDbManager(){ 16 | DatabaseManagerSwing.main( 17 | new String[] { "--url", "jdbc:hsqldb:mem:test", "--user", "sa", "--password", "", "--noexit"}); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/java/cz/jiripinkas/jba/util/MyUtil.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.util; 2 | 3 | import java.text.Normalizer; 4 | 5 | public final class MyUtil { 6 | 7 | private MyUtil() { 8 | } 9 | 10 | /** 11 | * Generate permalink (without http://www.yourweb.com prefix) 12 | * 13 | * @param input 14 | * Name (for example Java 101) 15 | * @return Permalink part (for example java-101) 16 | */ 17 | public static String generatePermalink(String input) { 18 | String permalink = input.toLowerCase().trim(); 19 | permalink = java.text.Normalizer.normalize(permalink, Normalizer.Form.NFD); 20 | permalink = permalink.replaceAll("\\p{InCombiningDiacriticalMarks}+", ""); 21 | permalink = permalink.replaceAll("[^\\p{Alpha}\\p{Digit}]+", "-"); 22 | permalink = permalink.replaceAll("^-", ""); 23 | permalink = permalink.replaceAll("-$", ""); 24 | return permalink; 25 | } 26 | 27 | /** 28 | * Returns public name in format "nick (name)". 29 | * If nick is empty, return "name". 30 | * If nick is too long, trim it (if trimLongNick is true) 31 | * @param nick 32 | * @param name 33 | * @param trimLongNick 34 | * @return 35 | */ 36 | public static String getPublicName(String nick, String name, boolean trimLongNick) { 37 | if (nick == null || nick.trim().isEmpty()) { 38 | return name; 39 | } 40 | if(trimLongNick) { 41 | if(nick.length() > 17) { 42 | nick = nick.substring(0, 17) + " ..."; 43 | } 44 | } 45 | return nick + " (" + name + ")"; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/apple-touch-icon.png -------------------------------------------------------------------------------- /src/main/resources/application-dev.properties: -------------------------------------------------------------------------------- 1 | spring.thymeleaf.cache=false 2 | spring.jpa.show-sql=true 3 | spring.jpa.generate-ddl=true 4 | server.port=8080 5 | spring.datasource.url=jdbc:hsqldb:mem:test;sql.syntax_pgs=true 6 | spring.datasource.username=sa 7 | spring.datasource.password= 8 | spring.datasource.driverClassName=org.hsqldb.jdbc.JDBCDriver 9 | -------------------------------------------------------------------------------- /src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | spring.thymeleaf.cache=true 2 | spring.jpa.hibernate.ddl-auto=update 3 | -------------------------------------------------------------------------------- /src/main/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=test 2 | spring.thymeleaf.cache=false 3 | spring.jpa.hibernate.ddl-auto=update 4 | spring.jpa.show-sql=true 5 | spring.datasource.url=jdbc:postgresql://localhost:5432/topjavablogs 6 | spring.datasource.username=postgres 7 | spring.datasource.password=admin 8 | spring.datasource.driverClassName=org.postgresql.Driver 9 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.jpa.open-in-view=false 2 | multipart.maxFileSize=512KB 3 | multipart.maxRequestSize=512KB 4 | 5 | spring.datasource.hikari.maximumPoolSize=5 -------------------------------------------------------------------------------- /src/main/resources/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/generic-blog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/generic-blog.png -------------------------------------------------------------------------------- /src/main/resources/java-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/java-logo.png -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - 8 | %msg%n 9 | 10 | 11 | 12 | 13 | 15 | debug.log 16 | 17 | 18 | %d{yyyy-MM-dd HH:mm:ss} - %msg%n 19 | 20 | 21 | 22 | 23 | 24 | debug.%d{yyyy-MM-dd}.%i.log 25 | 26 | 28 | 10MB 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/resources/security.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/resources/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/static/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/static/resources/css/bootstrap-dialog.min.css: -------------------------------------------------------------------------------- 1 | .bootstrap-dialog .modal-header{border-top-left-radius:4px;border-top-right-radius:4px}.bootstrap-dialog .bootstrap-dialog-title{color:#fff;display:inline-block}.bootstrap-dialog.type-default .bootstrap-dialog-title{color:#333}.bootstrap-dialog .bootstrap-dialog-title{font-size:16px}.bootstrap-dialog.size-large .bootstrap-dialog-title{font-size:24px}.bootstrap-dialog .bootstrap-dialog-close-button{float:right;filter:alpha(opacity=90);-moz-opacity:.9;-khtml-opacity:.9;opacity:.9}.bootstrap-dialog .bootstrap-dialog-close-button{font-size:20px}.bootstrap-dialog.size-large .bootstrap-dialog-close-button{font-size:30px}.bootstrap-dialog .bootstrap-dialog-close-button:hover{cursor:pointer;filter:alpha(opacity=100);-moz-opacity:1;-khtml-opacity:1;opacity:1}.bootstrap-dialog .bootstrap-dialog-message{font-size:14px}.bootstrap-dialog.size-large .bootstrap-dialog-message{font-size:18px}.bootstrap-dialog.type-default .modal-header{background-color:#fff}.bootstrap-dialog.type-info .modal-header{background-color:#5bc0de}.bootstrap-dialog.type-primary .modal-header{background-color:#428bca}.bootstrap-dialog.type-success .modal-header{background-color:#5cb85c}.bootstrap-dialog.type-warning .modal-header{background-color:#f0ad4e}.bootstrap-dialog.type-danger .modal-header{background-color:#d9534f}.bootstrap-dialog .bootstrap-dialog-button-icon{margin-right:3px}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0{-moz-transform:rotate(0)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0{-webkit-transform:rotate(0)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0{-o-transform:rotate(0)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0{-ms-transform:rotate(0)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0{transform:rotate(0)}100%{transform:rotate(359deg)}} -------------------------------------------------------------------------------- /src/main/resources/static/resources/css/custom.css: -------------------------------------------------------------------------------- 1 | .btn-file { 2 | position: relative; 3 | overflow: hidden; 4 | } 5 | 6 | .btn-file input[type=file] { 7 | position: absolute; 8 | top: 0; 9 | right: 0; 10 | min-width: 100%; 11 | min-height: 100%; 12 | font-size: 100px; 13 | text-align: right; 14 | filter: alpha(opacity = 0); 15 | opacity: 0; 16 | outline: none; 17 | background: white; 18 | cursor: inherit; 19 | display: block; 20 | } 21 | 22 | @media screen and (max-width: 786px) { 23 | .socialIconTwitter { 24 | display: none; 25 | } 26 | .socialIconFacebook { 27 | display: none; 28 | } 29 | .socialIconGooglePlus { 30 | display: none; 31 | } 32 | } 33 | 34 | @media screen and (min-width: 786px) { 35 | .socialIconTwitter { 36 | background-color: white; 37 | color: #32CCFE; 38 | padding-left: 5px; 39 | padding-right: 5px; 40 | cursor: pointer; 41 | } 42 | .socialIconFacebook { 43 | background-color: white; 44 | color: #3C599F; 45 | padding-right: 5px; 46 | cursor: pointer; 47 | } 48 | .socialIconGooglePlus { 49 | background-color: white; 50 | color: #CF3D2E; 51 | padding-right: 5px; 52 | cursor: pointer; 53 | } 54 | } 55 | 56 | .form-signin { 57 | max-width: 330px; 58 | padding: 15px; 59 | margin: 0 auto; 60 | } 61 | 62 | .form-signin .form-signin-heading,.form-signin .checkbox { 63 | margin-bottom: 10px; 64 | } 65 | 66 | .form-signin .checkbox { 67 | font-weight: normal; 68 | } 69 | 70 | .form-signin .form-control { 71 | position: relative; 72 | height: auto; 73 | -webkit-box-sizing: border-box; 74 | -moz-box-sizing: border-box; 75 | box-sizing: border-box; 76 | padding: 10px; 77 | font-size: 16px; 78 | } 79 | 80 | .form-signin .form-control:focus { 81 | z-index: 2; 82 | } 83 | 84 | .form-signin input[type="email"] { 85 | margin-bottom: -1px; 86 | border-bottom-right-radius: 0; 87 | border-bottom-left-radius: 0; 88 | } 89 | 90 | .form-signin input[type="password"] { 91 | margin-bottom: 10px; 92 | border-top-left-radius: 0; 93 | border-top-right-radius: 0; 94 | } 95 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/img/404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/static/resources/img/404.jpg -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/account.js: -------------------------------------------------------------------------------- 1 | 2 | JBA.account = {}; 3 | 4 | /* 5 | * jquery validation of blog form 6 | */ 7 | 8 | JBA.account.validate = { 9 | rules : { 10 | name : { 11 | required : true, 12 | minlength : 1 13 | }, 14 | url : { 15 | required : true, 16 | url : true, 17 | remote : { 18 | url : "/blog/available", 19 | type : "get", 20 | data : { 21 | url : function() { 22 | return $("#url") 23 | .val(); 24 | } 25 | } 26 | } 27 | }, 28 | homepageUrl : { 29 | required : true, 30 | minlength : 1, 31 | url : true 32 | }, 33 | shortName : { 34 | required : true, 35 | minlength : 1, 36 | remote : { 37 | url: "/blog/shortname/available", 38 | type: "get", 39 | data: { 40 | username: function() { 41 | return $("#shortName").val(); 42 | } 43 | } 44 | } 45 | } 46 | }, 47 | highlight : function(element) { 48 | $(element).closest('.form-group').removeClass('has-success').addClass('has-error'); 49 | }, 50 | unhighlight : function(element) { 51 | $(element).closest('.form-group').removeClass('has-error').addClass('has-success'); 52 | }, 53 | messages : { 54 | url : { 55 | remote : "Such blog already exists!" 56 | }, 57 | shortName: { 58 | remote: "Such short name already exists!" 59 | } 60 | } 61 | }; 62 | 63 | JBA.account.remove = function () { 64 | var origin = $(this); 65 | BootstrapDialog 66 | .show({ 67 | title : 'Really delete?', 68 | message : 'Really delete?', 69 | buttons : [ 70 | { 71 | label : 'Cancel', 72 | action : function(dialog) { 73 | dialog.close(); 74 | } 75 | }, 76 | { 77 | label : 'Delete', 78 | cssClass : 'btn-primary', 79 | action : function(dialog) { 80 | var blogId = origin.attr("id"); 81 | $.post("../blog/remove/" + blogId, 82 | function(data) { 83 | location.reload(true); // reload page 84 | }); 85 | dialog.close(); 86 | } 87 | } ] 88 | }); 89 | } 90 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/admin-categories.js: -------------------------------------------------------------------------------- 1 | 2 | JBA.adminCategories = {}; 3 | 4 | JBA.adminCategories.add = function(e) { 5 | $("#name").val(""); 6 | $("#shortName").val(""); 7 | $("#id").val("0"); 8 | $('#myModal').modal(); 9 | } 10 | 11 | JBA.adminCategories.edit = function(e) { 12 | $.get("/admin/categories/" + $(this).attr("id"), function (data) { 13 | $("#name").val(data.name); 14 | $("#shortName").val(data.shortName); 15 | $("#id").val(data.id); 16 | }); 17 | $('#myModal').modal(); 18 | } 19 | 20 | JBA.adminCategories.remove = function (e) { 21 | var origin = $(this); 22 | BootstrapDialog.show({ 23 | title: 'Really delete?', 24 | message: 'Really delete?', 25 | buttons: [{ 26 | label: 'Cancel', 27 | action: function(dialog) { 28 | dialog.close(); 29 | } 30 | }, { 31 | label: 'Delete', 32 | cssClass: 'btn-primary', 33 | action: function(dialog) { 34 | var categoryId = origin.attr("id"); 35 | $.post("/admin/categories/delete/" + categoryId, function (data) { 36 | location.reload(true); // reload page 37 | }); 38 | dialog.close(); 39 | } 40 | }] 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/ads.js: -------------------------------------------------------------------------------- 1 | var canRunAds = true; -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/blogs.js: -------------------------------------------------------------------------------- 1 | 2 | JBA.blogs = {}; 3 | 4 | /* 5 | * admininstrator functionality 6 | */ 7 | 8 | JBA.blogs.categorySelectChange = function (element) { 9 | var blogId = $(element).attr("id"); 10 | var categoryId = $(element).val(); 11 | $.post("admin/categories/set/" + blogId + "/cat/" + categoryId + ".json", function(data) { }); 12 | } 13 | 14 | JBA.blogs.remove = function (e) { 15 | var origin = $(e); 16 | BootstrapDialog.show({ 17 | title: 'Really delete?', 18 | message: 'Really delete?', 19 | buttons: [{ 20 | label: 'Cancel', 21 | action: function(dialog) { 22 | dialog.close(); 23 | } 24 | }, { 25 | label: 'Delete', 26 | cssClass: 'btn-primary', 27 | action: function(dialog) { 28 | var blogId = origin.attr("id"); 29 | $.post("blog/remove/" + blogId, function (data) { 30 | location.reload(true); // reload page 31 | }); 32 | dialog.close(); 33 | } 34 | }] 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/jquery.cookie.js: -------------------------------------------------------------------------------- 1 | !function(e){"function"==typeof define&&define.amd?define(["jquery"],e):e("object"==typeof exports?require("jquery"):jQuery)}(function(e){function n(e){return u.raw?e:encodeURIComponent(e)}function o(e){return u.raw?e:decodeURIComponent(e)}function i(e){return n(u.json?JSON.stringify(e):String(e))}function r(e){0===e.indexOf('"')&&(e=e.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return e=decodeURIComponent(e.replace(c," ")),u.json?JSON.parse(e):e}catch(n){}}function t(n,o){var i=u.raw?n:r(n);return e.isFunction(o)?o(i):i}var c=/\+/g,u=e.cookie=function(r,c,a){if(arguments.length>1&&!e.isFunction(c)){if(a=e.extend({},u.defaults,a),"number"==typeof a.expires){var f=a.expires,s=a.expires=new Date;s.setTime(+s+864e5*f)}return document.cookie=[n(r),"=",i(c),a.expires?"; expires="+a.expires.toUTCString():"",a.path?"; path="+a.path:"",a.domain?"; domain="+a.domain:"",a.secure?"; secure":""].join("")}for(var d=r?void 0:{},p=document.cookie?document.cookie.split("; "):[],m=0,x=p.length;x>m;m++){var l=p[m].split("="),g=o(l.shift()),k=l.join("=");if(r&&r===g){d=t(k,c);break}r||void 0===(k=t(k))||(d[g]=k)}return d};u.defaults={},e.removeCookie=function(n,o){return void 0===e.cookie(n)?!1:(e.cookie(n,"",e.extend({},o,{expires:-1})),!e.cookie(n))}}); -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/jquery.unveil.js: -------------------------------------------------------------------------------- 1 | !function(t){t.fn.unveil=function(i,e){function n(){var i=a.filter(function(){var i=t(this);if(!i.is(":hidden")){var e=o.scrollTop(),n=e+o.height(),r=i.offset().top,s=r+i.height();return s>=e-u&&n+u>=r}});r=i.trigger("unveil"),a=a.not(r)}var r,o=t(window),u=i||0,s=window.devicePixelRatio>1,l=s?"data-src-retina":"data-src",a=this;return this.one("unveil",function(){var t=this.getAttribute(l);t=t||this.getAttribute("data-src"),t&&(this.setAttribute("src",t),"function"==typeof e&&e.call(this))}),o.on("scroll.unveil resize.unveil lookup.unveil",n),n(),this}}(window.jQuery||window.Zepto); -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/main.js: -------------------------------------------------------------------------------- 1 | var JBA = {}; 2 | 3 | 4 | var unveilTreshold = 200; 5 | 6 | var currentPage = 0; 7 | 8 | var selectedCategories; 9 | 10 | var orderByCriteria = "latest"; 11 | 12 | var searchTxt = ''; 13 | 14 | /* 15 | * clever way to get homepage in javascript, thanks to: 16 | * http://james.padolsey.com/snippets/getting-a-fully-qualified-url/ 17 | */ 18 | function qualifyURL(url){ 19 | var img = document.createElement('img'); 20 | img.src = url; // set string url 21 | url = img.src; // get qualified url 22 | img.src = "http://"; // no server request 23 | return url; 24 | } 25 | 26 | /* 27 | * Called when user clicks on item URL 28 | */ 29 | function itemClick(e) { 30 | var itemId = $(e.target).attr("id"); 31 | if(!itemId) { 32 | // inside is , find closest 33 | itemId = $(e.target).closest("a").attr("id"); 34 | } 35 | var url = qualifyURL("/") + "inc-count"; 36 | $.post( 37 | url, 38 | { itemId: itemId }, 39 | function(data, status) { 40 | } 41 | ); 42 | } 43 | 44 | /* 45 | * Called when user clicks on like button. 46 | */ 47 | function itemLike(e) { 48 | e.preventDefault(); 49 | var itemId = $(e.target).attr("id"); 50 | if($.cookie("like_" + itemId) == "1") { 51 | unlike(itemId); 52 | } else if($.cookie("dislike_" + itemId) == "1") { 53 | undislike(itemId); 54 | like(itemId); 55 | } else { 56 | like(itemId); 57 | } 58 | } 59 | 60 | /* 61 | * Called when user clicks on dislike button. 62 | */ 63 | function itemDislike(e) { 64 | e.preventDefault(); 65 | var itemId = $(e.target).attr("id"); 66 | if($.cookie("dislike_" + itemId) == "1") { 67 | undislike(itemId); 68 | } else if($.cookie("like_" + itemId) == "1") { 69 | unlike(itemId); 70 | dislike(itemId); 71 | hide(itemId); 72 | } else { 73 | dislike(itemId); 74 | hide(itemId); 75 | } 76 | } 77 | 78 | function showCurrentState(id) { 79 | if($.cookie("like_" + id) == "1") { 80 | $(".icon_like_" + id).removeClass("fa-thumbs-o-up").addClass("fa-thumbs-up"); 81 | } 82 | if($.cookie("dislike_" + id) == "1") { 83 | $(".icon_dislike_" + id).removeClass("fa-thumbs-o-down").addClass("fa-thumbs-down"); 84 | hide(id); 85 | } 86 | } 87 | 88 | function hide(id) { 89 | // TODO 90 | // $(".icon_dislike_" + id).closest(".item-row").html("show disliked item"); 91 | } 92 | 93 | function unhide(id) { 94 | } 95 | 96 | var arrLikeProgress = []; 97 | 98 | function like(itemId) { 99 | if($.inArray(itemId, arrLikeProgress) !== -1) { 100 | return; 101 | } 102 | $(".icon_like_" + itemId).removeClass("fa-thumbs-o-up").addClass("fa-thumbs-up"); 103 | arrLikeProgress.push(itemId); 104 | var url = qualifyURL("/") + "social/like"; 105 | $.post( 106 | url, 107 | { itemId: itemId }, 108 | function(data, status) { 109 | $(".likeCount_" + itemId).text(data); 110 | $.cookie("like_" + itemId, "1", {expires: 30, path: '/'}); 111 | $.removeCookie("dislike_" + itemId); 112 | arrLikeProgress.splice($.inArray(itemId, arrLikeProgress), 1); 113 | } 114 | ); 115 | } 116 | 117 | function unlike(itemId) { 118 | if($.inArray(itemId, arrLikeProgress) !== -1) { 119 | return; 120 | } 121 | $(".icon_like_" + itemId).removeClass("fa-thumbs-up").addClass("fa-thumbs-o-up"); 122 | arrLikeProgress.push(itemId); 123 | var url = qualifyURL("/") + "social/unlike"; 124 | $.post( 125 | url, 126 | { itemId: itemId }, 127 | function(data, status) { 128 | $(".likeCount_" + itemId).text(data); 129 | $.removeCookie("like_" + itemId); 130 | arrLikeProgress.splice($.inArray(itemId, arrLikeProgress), 1); 131 | } 132 | ); 133 | } 134 | 135 | function dislike(itemId) { 136 | if($.inArray(itemId, arrLikeProgress) !== -1) { 137 | return; 138 | } 139 | $(".icon_dislike_" + itemId).removeClass("fa-thumbs-o-down").addClass("fa-thumbs-down"); 140 | arrLikeProgress.push(itemId); 141 | var url = qualifyURL("/") + "social/dislike"; 142 | $.post( 143 | url, 144 | { itemId: itemId }, 145 | function(data, status) { 146 | $(".dislikeCount_" + itemId).text(data); 147 | $.cookie("dislike_" + itemId, "1", {expires: 30, path: '/'}); 148 | $.removeCookie("like_" + itemId); 149 | arrLikeProgress.splice($.inArray(itemId, arrLikeProgress), 1); 150 | } 151 | ); 152 | } 153 | 154 | function undislike(itemId) { 155 | if($.inArray(itemId, arrLikeProgress) !== -1) { 156 | return; 157 | } 158 | $(".icon_dislike_" + itemId).removeClass("fa-thumbs-down").addClass("fa-thumbs-o-down"); 159 | arrLikeProgress.push(itemId); 160 | var url = qualifyURL("/") + "social/undislike"; 161 | $.post( 162 | url, 163 | { itemId: itemId }, 164 | function(data, status) { 165 | $(".dislikeCount_" + itemId).text(data); 166 | $.removeCookie("dislike_" + itemId, "1"); 167 | arrLikeProgress.splice($.inArray(itemId, arrLikeProgress), 1); 168 | } 169 | ); 170 | } 171 | 172 | function startRefresh() { 173 | $(".loadButton").text("load next 10 items"); 174 | $(".loadButton").css("display", "none"); 175 | $(".loadButton").after(""); 176 | } 177 | 178 | function finishRefresh(changedAnything) { 179 | if(!changedAnything) { 180 | $(".loadButton").text("there's nothing more"); 181 | } 182 | $(".loadButton").css("display", "inline"); 183 | $(".fa-spin").remove(); 184 | } 185 | 186 | function fbShare(url) { 187 | openWindow('http://www.facebook.com/sharer.php?u=' + url); 188 | } 189 | 190 | function twShare(url, title) { 191 | openWindow('https://twitter.com/intent/tweet?text=' + title + '&url=' + url); 192 | } 193 | 194 | function gpShare(url) { 195 | openWindow('https://plus.google.com/share?url=' + url); 196 | } 197 | 198 | function openWindow(url) { 199 | var winWidth = 660; 200 | var winHeight = 330; 201 | var winTop = (screen.height / 2) - (winHeight / 2); 202 | var winLeft = (screen.width / 2) - (winWidth / 2); 203 | window.open(url, 'Share', 'top=' + winTop + ',left=' + winLeft + ',toolbar=0,status=0,width=' + winWidth + ',height=' + winHeight); 204 | } 205 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/news.js: -------------------------------------------------------------------------------- 1 | 2 | JBA.news = {}; 3 | 4 | /* 5 | * administrator functionality 6 | */ 7 | 8 | JBA.news.remove = function (e) { 9 | var origin = $(e); 10 | BootstrapDialog.show({ 11 | title: 'Really delete?', 12 | message: 'Really delete?', 13 | buttons: [{ 14 | label: 'Cancel', 15 | action: function(dialog) { 16 | dialog.close(); 17 | } 18 | }, { 19 | label: 'Delete', 20 | cssClass: 'btn-primary', 21 | action: function(dialog) { 22 | var newsId = origin.attr("id"); 23 | $.post("/admin/news/delete/" + newsId, function (data) { 24 | location.reload(true); // reload page 25 | }); 26 | dialog.close(); 27 | } 28 | }] 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/register.js: -------------------------------------------------------------------------------- 1 | 2 | JBA.register = {}; 3 | 4 | /* 5 | * registration form validation 6 | */ 7 | 8 | JBA.register.validate = { 9 | rules: { 10 | name: { 11 | required : true, 12 | minlength : 3, 13 | remote : { 14 | url: "/register/available", 15 | type: "get", 16 | data: { 17 | username: function() { 18 | return $("#name").val(); 19 | } 20 | } 21 | } 22 | }, 23 | email: { 24 | required : true, 25 | email: true 26 | }, 27 | password: { 28 | required : true, 29 | minlength : 5 30 | }, 31 | password_again: { 32 | required : true, 33 | minlength : 5, 34 | equalTo: "#password" 35 | } 36 | }, 37 | highlight: function(element) { 38 | $(element).closest('.form-group').removeClass('has-success').addClass('has-error'); 39 | }, 40 | unhighlight: function(element) { 41 | $(element).closest('.form-group').removeClass('has-error').addClass('has-success'); 42 | }, 43 | messages: { 44 | name: { 45 | remote: "Such username already exists!" 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/resources/static/resources/js/users.js: -------------------------------------------------------------------------------- 1 | 2 | JBA.users = {} 3 | 4 | JBA.users.remove = function () { 5 | var origin = $(this); 6 | BootstrapDialog.show({ 7 | title: 'Really delete?', 8 | message: 'Really delete?', 9 | buttons: [{ 10 | label: 'Cancel', 11 | action: function(dialog) { 12 | dialog.close(); 13 | } 14 | }, { 15 | label: 'Delete', 16 | cssClass: 'btn-primary', 17 | action: function(dialog) { 18 | var userId = origin.attr("id"); 19 | $.post("users/remove/" + userId, function (data) { 20 | location.reload(true); // reload page 21 | }); 22 | dialog.close(); 23 | } 24 | }] 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-apollo.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["com",/^#[^\n\r]*/,null,"#"],["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"']],[["kwd",/^(?:ADS|AD|AUG|BZF|BZMF|CAE|CAF|CA|CCS|COM|CS|DAS|DCA|DCOM|DCS|DDOUBL|DIM|DOUBLE|DTCB|DTCF|DV|DXCH|EDRUPT|EXTEND|INCR|INDEX|NDX|INHINT|LXCH|MASK|MSK|MP|MSU|NOOP|OVSK|QXCH|RAND|READ|RELINT|RESUME|RETURN|ROR|RXOR|SQUARE|SU|TCR|TCAA|OVSK|TCF|TC|TS|WAND|WOR|WRITE|XCH|XLQ|XXALQ|ZL|ZQ|ADD|ADZ|SUB|SUZ|MPY|MPR|MPZ|DVP|COM|ABS|CLA|CLZ|LDQ|STO|STQ|ALS|LLS|LRS|TRA|TSQ|TMI|TOV|AXT|TIX|DLY|INP|OUT)\s/, 2 | null],["typ",/^(?:-?GENADR|=MINUS|2BCADR|VN|BOF|MM|-?2CADR|-?[1-6]DNADR|ADRES|BBCON|[ES]?BANK=?|BLOCK|BNKSUM|E?CADR|COUNT\*?|2?DEC\*?|-?DNCHAN|-?DNPTR|EQUALS|ERASE|MEMORY|2?OCT|REMADR|SETLOC|SUBRO|ORG|BSS|BES|SYN|EQU|DEFINE|END)\s/,null],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[!-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["apollo","agc","aea"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-basic.js: -------------------------------------------------------------------------------- 1 | var a=null; 2 | PR.registerLangHandler(PR.createSimpleLexer([["str",/^"(?:[^\n\r"\\]|\\.)*(?:"|$)/,a,'"'],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["com",/^REM[^\n\r]*/,a],["kwd",/^\b(?:AND|CLOSE|CLR|CMD|CONT|DATA|DEF ?FN|DIM|END|FOR|GET|GOSUB|GOTO|IF|INPUT|LET|LIST|LOAD|NEW|NEXT|NOT|ON|OPEN|OR|POKE|PRINT|READ|RESTORE|RETURN|RUN|SAVE|STEP|STOP|SYS|THEN|TO|VERIFY|WAIT)\b/,a],["pln",/^[a-z][^\W_]?(?:\$|%)?/i,a],["lit",/^(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/i,a,"0123456789"],["pun", 3 | /^.[^\s\w"$%.]*/,a]]),["basic","cbm"]); 4 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-clj.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2011 Google Inc. 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | var a=null; 17 | PR.registerLangHandler(PR.createSimpleLexer([["opn",/^[([{]+/,a,"([{"],["clo",/^[)\]}]+/,a,")]}"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:def|if|do|let|quote|var|fn|loop|recur|throw|try|monitor-enter|monitor-exit|defmacro|defn|defn-|macroexpand|macroexpand-1|for|doseq|dosync|dotimes|and|or|when|not|assert|doto|proxy|defstruct|first|rest|cons|defprotocol|deftype|defrecord|reify|defmulti|defmethod|meta|with-meta|ns|in-ns|create-ns|import|intern|refer|alias|namespace|resolve|ref|deref|refset|new|set!|memfn|to-array|into-array|aset|gen-class|reduce|map|filter|find|nil?|empty?|hash-map|hash-set|vec|vector|seq|flatten|reverse|assoc|dissoc|list|list?|disj|get|union|difference|intersection|extend|extend-type|extend-protocol|prn)\b/,a], 18 | ["typ",/^:[\dA-Za-z-]+/]]),["clj"]); 19 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n\u000c"]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]+)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//], 2 | ["com",/^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}\b/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-dart.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"]],[["com",/^#!.*/],["kwd",/^\b(?:import|library|part of|part|as|show|hide)\b/i],["com",/^\/\/.*/],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["kwd",/^\b(?:class|interface)\b/i],["kwd",/^\b(?:assert|break|case|catch|continue|default|do|else|finally|for|if|in|is|new|return|super|switch|this|throw|try|while)\b/i],["kwd",/^\b(?:abstract|const|extends|factory|final|get|implements|native|operator|set|static|typedef|var)\b/i], 2 | ["typ",/^\b(?:bool|double|dynamic|int|num|object|string|void)\b/i],["kwd",/^\b(?:false|null|true)\b/i],["str",/^r?'''[\S\s]*?[^\\]'''/],["str",/^r?"""[\S\s]*?[^\\]"""/],["str",/^r?'('|[^\n\f\r]*?[^\\]')/],["str",/^r?"("|[^\n\f\r]*?[^\\]")/],["pln",/^[$_a-z]\w*/i],["pun",/^[!%&*+/:<-?^|~-]/],["lit",/^\b0x[\da-f]+/i],["lit",/^\b\d+(?:\.\d*)?(?:e[+-]?\d+)?/i],["lit",/^\b\.\d+(?:e[+-]?\d+)?/i],["pun",/^[(),.;[\]{}]/]]), 3 | ["dart"]); 4 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-erlang.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["lit",/^[a-z]\w*/],["lit",/^'(?:[^\n\f\r'\\]|\\[^&])+'?/,null,"'"],["lit",/^\?[^\t\n ({]+/,null,"?"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^%[^\n]*/],["kwd",/^(?:module|attributes|do|let|in|letrec|apply|call|primop|case|of|end|when|fun|try|catch|receive|after|char|integer|float,atom,string,var)\b/], 2 | ["kwd",/^-[_a-z]+/],["typ",/^[A-Z_]\w*/],["pun",/^[,.;]/]]),["erlang","erl"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-go.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["pln",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])+(?:'|$)|`[^`]*(?:`|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\/\*[\S\s]*?\*\/)/],["pln",/^(?:[^"'/`]|\/(?![*/]))+/]]),["go"]); 2 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-hs.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t-\r ]+/,null,"\t\n\u000b\u000c\r "],["str",/^"(?:[^\n\f\r"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^\n\f\r'\\]|\\[^&])'?/,null,"'"],["lit",/^(?:0o[0-7]+|0x[\da-f]+|\d+(?:\.\d+)?(?:e[+-]?\d+)?)/i,null,"0123456789"]],[["com",/^(?:--+[^\n\f\r]*|{-(?:[^-]|-+[^}-])*-})/],["kwd",/^(?:case|class|data|default|deriving|do|else|if|import|in|infix|infixl|infixr|instance|let|module|newtype|of|then|type|where|_)(?=[^\d'A-Za-z]|$)/, 2 | null],["pln",/^(?:[A-Z][\w']*\.)*[A-Za-z][\w']*/],["pun",/^[^\d\t-\r "'A-Za-z]+/]]),["hs"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-lisp.js: -------------------------------------------------------------------------------- 1 | var a=null; 2 | PR.registerLangHandler(PR.createSimpleLexer([["opn",/^\(+/,a,"("],["clo",/^\)+/,a,")"],["com",/^;[^\n\r]*/,a,";"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:block|c[ad]+r|catch|con[ds]|def(?:ine|un)|do|eq|eql|equal|equalp|eval-when|flet|format|go|if|labels|lambda|let|load-time-value|locally|macrolet|multiple-value-call|nil|progn|progv|quote|require|return-from|setq|symbol-macrolet|t|tagbody|the|throw|unwind)\b/,a], 3 | ["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit",/^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["cl","el","lisp","lsp","scm","ss","rkt"]); 4 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-llvm.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^!?"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["com",/^;[^\n\r]*/,null,";"]],[["pln",/^[!%@](?:[$\-.A-Z_a-z][\w$\-.]*|\d+)/],["kwd",/^[^\W\d]\w*/,null],["lit",/^\d+\.\d+/],["lit",/^(?:\d+|0[Xx][\dA-Fa-f]+)/],["pun",/^[(-*,:<->[\]{}]|\.\.\.$/]]),["llvm","ll"]); 2 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-lua.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$))/,null,"\"'"]],[["com",/^--(?:\[(=*)\[[\S\s]*?(?:]\1]|$)|[^\n\r]*)/],["str",/^\[(=*)\[[\S\s]*?(?:]\1]|$)/],["kwd",/^(?:and|break|do|else|elseif|end|false|for|function|if|in|local|nil|not|or|repeat|return|then|true|until|while)\b/,null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i], 2 | ["pln",/^[_a-z]\w*/i],["pun",/^[^\w\t\n\r \xa0][^\w\t\n\r "'+=\xa0-]*/]]),["lua"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-ml.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^#(?:if[\t\n\r \xa0]+(?:[$_a-z][\w']*|``[^\t\n\r`]*(?:``|$))|else|endif|light)/i,null,"#"],["str",/^(?:"(?:[^"\\]|\\[\S\s])*(?:"|$)|'(?:[^'\\]|\\[\S\s])(?:'|$))/,null,"\"'"]],[["com",/^(?:\/\/[^\n\r]*|\(\*[\S\s]*?\*\))/],["kwd",/^(?:abstract|and|as|assert|begin|class|default|delegate|do|done|downcast|downto|elif|else|end|exception|extern|false|finally|for|fun|function|if|in|inherit|inline|interface|internal|lazy|let|match|member|module|mutable|namespace|new|null|of|open|or|override|private|public|rec|return|static|struct|then|to|true|try|type|upcast|use|val|void|when|while|with|yield|asr|land|lor|lsl|lsr|lxor|mod|sig|atomic|break|checked|component|const|constraint|constructor|continue|eager|event|external|fixed|functor|global|include|method|mixin|object|parallel|process|protected|pure|sealed|trait|virtual|volatile)\b/], 2 | ["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^(?:[_a-z][\w']*[!#?]?|``[^\t\n\r`]*(?:``|$))/i],["pun",/^[^\w\t\n\r "'\xa0]+/]]),["fs","ml"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-mumps.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"]|\\.)*"/,null,'"']],[["com",/^;[^\n\r]*/,null,";"],["dec",/^\$(?:d|device|ec|ecode|es|estack|et|etrap|h|horolog|i|io|j|job|k|key|p|principal|q|quit|st|stack|s|storage|sy|system|t|test|tl|tlevel|tr|trestart|x|y|z[a-z]*|a|ascii|c|char|d|data|e|extract|f|find|fn|fnumber|g|get|j|justify|l|length|na|name|o|order|p|piece|ql|qlength|qs|qsubscript|q|query|r|random|re|reverse|s|select|st|stack|t|text|tr|translate|nan)\b/i, 2 | null],["kwd",/^(?:[^$]b|break|c|close|d|do|e|else|f|for|g|goto|h|halt|h|hang|i|if|j|job|k|kill|l|lock|m|merge|n|new|o|open|q|quit|r|read|s|set|tc|tcommit|tre|trestart|tro|trollback|ts|tstart|u|use|v|view|w|write|x|xecute)\b/i,null],["lit",/^[+-]?(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?/i],["pln",/^[a-z][^\W_]*/i],["pun",/^[^\w\t\n\r"$%;^\xa0]|_/]]),["mumps"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-n.js: -------------------------------------------------------------------------------- 1 | var a=null; 2 | PR.registerLangHandler(PR.createSimpleLexer([["str",/^(?:'(?:[^\n\r'\\]|\\.)*'|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,a,'"'],["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,a,"#"],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["str",/^@"(?:[^"]|"")*(?:"|$)/,a],["str",/^<#[^#>]*(?:#>|$)/,a],["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,a],["com",/^\/\/[^\n\r]*/,a],["com",/^\/\*[\S\s]*?(?:\*\/|$)/, 3 | a],["kwd",/^(?:abstract|and|as|base|catch|class|def|delegate|enum|event|extern|false|finally|fun|implements|interface|internal|is|macro|match|matches|module|mutable|namespace|new|null|out|override|params|partial|private|protected|public|ref|sealed|static|struct|syntax|this|throw|true|try|type|typeof|using|variant|virtual|volatile|when|where|with|assert|assert2|async|break|checked|continue|do|else|ensures|for|foreach|if|late|lock|new|nolate|otherwise|regexp|repeat|requires|return|surroundwith|unchecked|unless|using|while|yield)\b/, 4 | a],["typ",/^(?:array|bool|byte|char|decimal|double|float|int|list|long|object|sbyte|short|string|ulong|uint|ufloat|ulong|ushort|void)\b/,a],["lit",/^@[$_a-z][\w$@]*/i,a],["typ",/^@[A-Z]+[a-z][\w$@]*/,a],["pln",/^'?[$_a-z][\w$@]*/i,a],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,a,"0123456789"],["pun",/^.[^\s\w"-$'./@`]*/,a]]),["n","nemerle"]); 5 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-pascal.js: -------------------------------------------------------------------------------- 1 | var a=null; 2 | PR.registerLangHandler(PR.createSimpleLexer([["str",/^'(?:[^\n\r'\\]|\\.)*(?:'|$)/,a,"'"],["pln",/^\s+/,a," \r\n\t\u00a0"]],[["com",/^\(\*[\S\s]*?(?:\*\)|$)|^{[\S\s]*?(?:}|$)/,a],["kwd",/^(?:absolute|and|array|asm|assembler|begin|case|const|constructor|destructor|div|do|downto|else|end|external|for|forward|function|goto|if|implementation|in|inline|interface|interrupt|label|mod|not|object|of|or|packed|procedure|program|record|repeat|set|shl|shr|then|to|type|unit|until|uses|var|virtual|while|with|xor)\b/i,a], 3 | ["lit",/^(?:true|false|self|nil)/i,a],["pln",/^[a-z][^\W_]*/i,a],["lit",/^(?:\$[\da-f]+|(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?)/i,a,"0123456789"],["pun",/^.[^\s\w$'./@]*/,a]]),["pascal"]); 4 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-proto.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.sourceDecorator({keywords:"bytes,default,double,enum,extend,extensions,false,group,import,max,message,option,optional,package,repeated,required,returns,rpc,service,syntax,to,true",types:/^(bool|(double|s?fixed|[su]?int)(32|64)|float|string)\b/,cStyleComments:!0}),["proto"]); 2 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-r.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,null,'"'],["str",/^'(?:[^'\\]|\\[\S\s])*(?:'|$)/,null,"'"]],[["com",/^#.*/],["kwd",/^(?:if|else|for|while|repeat|in|next|break|return|switch|function)(?![\w.])/],["lit",/^0[Xx][\dA-Fa-f]+([Pp]\d+)?[Li]?/],["lit",/^[+-]?(\d+(\.\d+)?|\.\d+)([Ee][+-]?\d+)?[Li]?/],["lit",/^(?:NULL|NA(?:_(?:integer|real|complex|character)_)?|Inf|TRUE|FALSE|NaN|\.\.(?:\.|\d+))(?![\w.])/], 2 | ["pun",/^(?:<>?|-|==|<=|>=|<|>|&&?|!=|\|\|?|[!*+/^]|%.*?%|[$=@~]|:{1,3}|[(),;?[\]{}])/],["pln",/^(?:[A-Za-z]+[\w.]*|\.[^\W\d][\w.]*)(?![\w.])/],["str",/^`.+`/]]),["r","s","R","S","Splus"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-rd.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^%[^\n\r]*/,null,"%"]],[["lit",/^\\(?:cr|l?dots|R|tab)\b/],["kwd",/^\\[@-Za-z]+/],["kwd",/^#(?:ifn?def|endif)/],["pln",/^\\[{}]/],["pun",/^[()[\]{}]+/]]),["Rd","rd"]); 2 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-scala.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^"(?:""(?:""?(?!")|[^"\\]|\\.)*"{0,3}|(?:[^\n\r"\\]|\\.)*"?)/,null,'"'],["lit",/^`(?:[^\n\r\\`]|\\.)*`?/,null,"`"],["pun",/^[!#%&(--:-@[-^{-~]+/,null,"!#%&()*+,-:;<=>?@[\\]^{|}~"]],[["str",/^'(?:[^\n\r'\\]|\\(?:'|[^\n\r']+))'/],["lit",/^'[$A-Z_a-z][\w$]*(?![\w$'])/],["kwd",/^(?:abstract|case|catch|class|def|do|else|extends|final|finally|for|forSome|if|implicit|import|lazy|match|new|object|override|package|private|protected|requires|return|sealed|super|throw|trait|try|type|val|var|while|with|yield)\b/], 2 | ["lit",/^(?:true|false|null|this)\b/],["lit",/^(?:0(?:[0-7]+|x[\da-f]+)l?|(?:0|[1-9]\d*)(?:(?:\.\d+)?(?:e[+-]?\d+)?f?|l?)|\\.\d+(?:e[+-]?\d+)?f?)/i],["typ",/^[$_]*[A-Z][\d$A-Z_]*[a-z][\w$]*/],["pln",/^[$A-Z_a-z][\w$]*/],["com",/^\/(?:\/.*|\*(?:\/|\**[^*/])*(?:\*+\/?)?)/],["pun",/^(?:\.+|\/)/]]),["scala"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-sql.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["str",/^(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')/,null,"\"'"]],[["com",/^(?:--[^\n\r]*|\/\*[\S\s]*?(?:\*\/|$))/],["kwd",/^(?:add|all|alter|and|any|apply|as|asc|authorization|backup|begin|between|break|browse|bulk|by|cascade|case|check|checkpoint|close|clustered|coalesce|collate|column|commit|compute|connect|constraint|contains|containstable|continue|convert|create|cross|current|current_date|current_time|current_timestamp|current_user|cursor|database|dbcc|deallocate|declare|default|delete|deny|desc|disk|distinct|distributed|double|drop|dummy|dump|else|end|errlvl|escape|except|exec|execute|exists|exit|fetch|file|fillfactor|following|for|foreign|freetext|freetexttable|from|full|function|goto|grant|group|having|holdlock|identity|identitycol|identity_insert|if|in|index|inner|insert|intersect|into|is|join|key|kill|left|like|lineno|load|match|matched|merge|natural|national|nocheck|nonclustered|nocycle|not|null|nullif|of|off|offsets|on|open|opendatasource|openquery|openrowset|openxml|option|or|order|outer|over|partition|percent|pivot|plan|preceding|precision|primary|print|proc|procedure|public|raiserror|read|readtext|reconfigure|references|replication|restore|restrict|return|revoke|right|rollback|rowcount|rowguidcol|rows?|rule|save|schema|select|session_user|set|setuser|shutdown|some|start|statistics|system_user|table|textsize|then|to|top|tran|transaction|trigger|truncate|tsequal|unbounded|union|unique|unpivot|update|updatetext|use|user|using|values|varying|view|waitfor|when|where|while|with|within|writetext|xml)(?=[^\w-]|$)/i, 2 | null],["lit",/^[+-]?(?:0x[\da-f]+|(?:\.\d+|\d+(?:\.\d*)?)(?:e[+-]?\d+)?)/i],["pln",/^[_a-z][\w-]*/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'+\xa0-]*/]]),["sql"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-tcl.js: -------------------------------------------------------------------------------- 1 | var a=null; 2 | PR.registerLangHandler(PR.createSimpleLexer([["opn",/^{+/,a,"{"],["clo",/^}+/,a,"}"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^[\t\n\r \xa0]+/,a,"\t\n\r \u00a0"],["str",/^"(?:[^"\\]|\\[\S\s])*(?:"|$)/,a,'"']],[["kwd",/^(?:after|append|apply|array|break|case|catch|continue|error|eval|exec|exit|expr|for|foreach|if|incr|info|proc|return|set|switch|trace|uplevel|upvar|while)\b/,a],["lit",/^[+-]?(?:[#0]x[\da-f]+|\d+\/\d+|(?:\.\d+|\d+(?:\.\d*)?)(?:[de][+-]?\d+)?)/i],["lit", 3 | /^'(?:-*(?:\w|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?)?/],["pln",/^-*(?:[_a-z]|\\[!-~])(?:[\w-]*|\\[!-~])[!=?]?/i],["pun",/^[^\w\t\n\r "'-);\\\xa0]+/]]),["tcl"]); 4 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-tex.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"],["com",/^%[^\n\r]*/,null,"%"]],[["kwd",/^\\[@-Za-z]+/],["kwd",/^\\./],["typ",/^[$&]/],["lit",/[+-]?(?:\.\d+|\d+(?:\.\d*)?)(cm|em|ex|in|pc|pt|bp|mm)/i],["pun",/^[()=[\]{}]+/]]),["latex","tex"]); 2 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-vb.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0\u2028\u2029]+/,null,"\t\n\r \u00a0\u2028\u2029"],["str",/^(?:["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})(?:["\u201c\u201d]c|$)|["\u201c\u201d](?:[^"\u201c\u201d]|["\u201c\u201d]{2})*(?:["\u201c\u201d]|$))/i,null,'"\u201c\u201d'],["com",/^['\u2018\u2019](?:_(?:\r\n?|[^\r]?)|[^\n\r_\u2028\u2029])*/,null,"'\u2018\u2019"]],[["kwd",/^(?:addhandler|addressof|alias|and|andalso|ansi|as|assembly|auto|boolean|byref|byte|byval|call|case|catch|cbool|cbyte|cchar|cdate|cdbl|cdec|char|cint|class|clng|cobj|const|cshort|csng|cstr|ctype|date|decimal|declare|default|delegate|dim|directcast|do|double|each|else|elseif|end|endif|enum|erase|error|event|exit|finally|for|friend|function|get|gettype|gosub|goto|handles|if|implements|imports|in|inherits|integer|interface|is|let|lib|like|long|loop|me|mod|module|mustinherit|mustoverride|mybase|myclass|namespace|new|next|not|notinheritable|notoverridable|object|on|option|optional|or|orelse|overloads|overridable|overrides|paramarray|preserve|private|property|protected|public|raiseevent|readonly|redim|removehandler|resume|return|select|set|shadows|shared|short|single|static|step|stop|string|structure|sub|synclock|then|throw|to|try|typeof|unicode|until|variant|wend|when|while|with|withevents|writeonly|xor|endif|gosub|let|variant|wend)\b/i, 2 | null],["com",/^rem\b.*/i],["lit",/^(?:true\b|false\b|nothing\b|\d+(?:e[+-]?\d+[dfr]?|[dfilrs])?|(?:&h[\da-f]+|&o[0-7]+)[ils]?|\d*\.\d+(?:e[+-]?\d+)?[dfr]?|#\s+(?:\d+[/-]\d+[/-]\d+(?:\s+\d+:\d+(?::\d+)?(\s*(?:am|pm))?)?|\d+:\d+(?::\d+)?(\s*(?:am|pm))?)\s+#)/i],["pln",/^(?:(?:[a-z]|_\w)\w*(?:\[[!#%&@]+])?|\[(?:[a-z]|_\w)\w*])/i],["pun",/^[^\w\t\n\r "'[\]\xa0\u2018\u2019\u201c\u201d\u2028\u2029]+/],["pun",/^(?:\[|])/]]),["vb","vbs"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-vhdl.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\r \xa0]+/,null,"\t\n\r \u00a0"]],[["str",/^(?:[box]?"(?:[^"]|"")*"|'.')/i],["com",/^--[^\n\r]*/],["kwd",/^(?:abs|access|after|alias|all|and|architecture|array|assert|attribute|begin|block|body|buffer|bus|case|component|configuration|constant|disconnect|downto|else|elsif|end|entity|exit|file|for|function|generate|generic|group|guarded|if|impure|in|inertial|inout|is|label|library|linkage|literal|loop|map|mod|nand|new|next|nor|not|null|of|on|open|or|others|out|package|port|postponed|procedure|process|pure|range|record|register|reject|rem|report|return|rol|ror|select|severity|shared|signal|sla|sll|sra|srl|subtype|then|to|transport|type|unaffected|units|until|use|variable|wait|when|while|with|xnor|xor)(?=[^\w-]|$)/i, 2 | null],["typ",/^(?:bit|bit_vector|character|boolean|integer|real|time|string|severity_level|positive|natural|signed|unsigned|line|text|std_u?logic(?:_vector)?)(?=[^\w-]|$)/i,null],["typ",/^'(?:active|ascending|base|delayed|driving|driving_value|event|high|image|instance_name|last_active|last_event|last_value|left|leftof|length|low|path_name|pos|pred|quiet|range|reverse_range|right|rightof|simple_name|stable|succ|transaction|val|value)(?=[^\w-]|$)/i,null],["lit",/^\d+(?:_\d+)*(?:#[\w.\\]+#(?:[+-]?\d+(?:_\d+)*)?|(?:\.\d+(?:_\d+)*)?(?:e[+-]?\d+(?:_\d+)*)?)/i], 3 | ["pln",/^(?:[a-z]\w*|\\[^\\]*\\)/i],["pun",/^[^\w\t\n\r "'\xa0][^\w\t\n\r "'\xa0-]*/]]),["vhdl","vhd"]); 4 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-wiki.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\d\t a-gi-z\xa0]+/,null,"\t \u00a0abcdefgijklmnopqrstuvwxyz0123456789"],["pun",/^[*=[\]^~]+/,null,"=*~^[]"]],[["lang-wiki.meta",/(?:^^|\r\n?|\n)(#[a-z]+)\b/],["lit",/^[A-Z][a-z][\da-z]+[A-Z][a-z][^\W_]+\b/],["lang-",/^{{{([\S\s]+?)}}}/],["lang-",/^`([^\n\r`]+)`/],["str",/^https?:\/\/[^\s#/?]*(?:\/[^\s#?]*)?(?:\?[^\s#]*)?(?:#\S*)?/i],["pln",/^(?:\r\n|[\S\s])[^\n\r#*=A-[^`h{~]*/]]),["wiki"]); 2 | PR.registerLangHandler(PR.createSimpleLexer([["kwd",/^#[a-z]+/i,null,"#"]],[]),["wiki.meta"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/lang-yaml.js: -------------------------------------------------------------------------------- 1 | var a=null; 2 | PR.registerLangHandler(PR.createSimpleLexer([["pun",/^[:>?|]+/,a,":|>?"],["dec",/^%(?:YAML|TAG)[^\n\r#]+/,a,"%"],["typ",/^&\S+/,a,"&"],["typ",/^!\S*/,a,"!"],["str",/^"(?:[^"\\]|\\.)*(?:"|$)/,a,'"'],["str",/^'(?:[^']|'')*(?:'|$)/,a,"'"],["com",/^#[^\n\r]*/,a,"#"],["pln",/^\s+/,a," \t\r\n"]],[["dec",/^(?:---|\.\.\.)(?:[\n\r]|$)/],["pun",/^-/],["kwd",/^\w+:[\n\r ]/],["pln",/^\w+/]]),["yaml","yml"]); 3 | -------------------------------------------------------------------------------- /src/main/resources/static/resources/prettyprint/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /src/main/resources/static/yandex_60a2aaff053bad91.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RameshMF/java-blog-aggregator-boot/c4f229c61810ec2b2bcd88e9d37596737c8cb200/src/main/resources/static/yandex_60a2aaff053bad91.txt -------------------------------------------------------------------------------- /src/main/resources/templates/account.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 |

18 | 19 |
Add only a blog, which isn't already 20 | tracked. Your submission will be reviewed by an administrator and if 21 | accepted, news from the blog will be displayed on front page. If not 22 | accepted, the blog will be deleted.
23 | 24 |
25 | 92 |
93 | 94 |
95 |
96 | 97 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 118 | 121 | 125 | 126 | 127 |
nameoperationsaccepted?
116 | 117 | 119 | 120 | 122 | edit 123 | 124 |
128 | 129 | 130 | 131 |
132 | 133 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin-categories.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 19 | 20 |
21 | 22 | 23 | 52 |
53 | 54 |

55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 74 | 75 | 76 |
nameoperations
67 | 70 | 73 |
77 | 78 | 85 | 86 | 87 | 88 |
89 | 90 | -------------------------------------------------------------------------------- /src/main/resources/templates/admin-detail.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
Saved!
16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | 28 | error 29 |
30 |
31 | 32 |
33 | 34 |
35 | 36 | error 37 |
38 |
39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 |
47 | 48 | -------------------------------------------------------------------------------- /src/main/resources/templates/blog-form.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
Saved!
16 | 17 | 18 | 19 | 20 |
21 | 22 | Select icon (50 x 50 px) 23 | 24 | 25 |
26 | 27 |
28 | 29 |

30 |
31 | 32 |
33 | 34 | 35 |
36 | 37 |
38 | 39 | error 40 |
41 |
42 |
43 | 44 |
45 | 46 | error 47 |
48 |
49 |
50 | 51 |
52 | 53 | error 54 |
55 |
56 |
57 | 58 |
59 | 60 | error 61 |
62 |
63 |
64 | 65 |
66 | 67 | error 68 |
69 |
70 | 71 |
72 | 73 |
74 | 75 |
76 |
77 |
78 | 79 |
80 | 81 |
82 |
83 |
84 | 85 |
86 | 87 |
88 |
89 |
90 | 91 | 92 | 93 |
94 | 95 | 96 | 97 |
98 | 99 | -------------------------------------------------------------------------------- /src/main/resources/templates/blogs.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 |

Errors:

18 |
    19 | 20 |
  • 21 | 22 |
  • 23 |
    24 |
25 |
26 | 27 |

All blogs:

28 | 29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 58 | 67 | 70 | 71 | 74 | 92 | 93 | 94 | 95 |
blogpopularitycategoryuseredit
48 | 49 | 50 | 51 | 52 |
53 | 54 | 55 | 56 | 57 |
59 | 60 |
61 | archived 62 |
63 | 64 | 65 | 66 |
68 | 69 | 72 | 73 | 75 | 76 | edit 77 | 78 | 81 | 82 | category: 83 | 91 |
96 | 97 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | 114 | -------------------------------------------------------------------------------- /src/main/resources/templates/configuration.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
Saved!
16 | 17 | 18 |
19 | 20 | Select icon (50 x 50 px) 21 | 22 | 23 |
24 |
25 | logo 26 | 27 | 28 |
29 | 30 |
31 | 32 | 33 |
34 | 35 | Select icon (32 x 32 px) 36 | 37 | 38 |
39 |
40 | favicon 41 | 42 | 43 |
44 | 45 |
46 | 47 | 48 |
49 | 50 | Select icon (180 x 180 px) 51 | 52 | 53 |
54 |
55 | appleTouchIcon 56 | 57 | 58 |
59 | 60 |

61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 |
70 | 71 |
72 | 73 |
74 | 75 |
76 |
77 | 78 |
79 | 80 |
81 | 82 |
83 |
84 | 85 |
86 | 87 |
88 | 89 |
90 |
91 | 92 |
93 | 94 |
95 | 96 |
97 |
98 | 99 |
100 | 101 |
102 | 103 |
104 |
105 | 106 |
107 | 108 |
109 | 110 |
111 |
112 | 113 |
114 | 115 |
116 | 117 |
118 |
119 | 120 |
121 | 122 |
123 | 124 |
125 |
126 | 127 |
128 | 129 |
130 | 131 |
132 |
133 | 134 |
135 | 136 |
137 | 138 |
139 |
140 | 141 |
142 | 143 |
144 | 145 |
146 |
147 | 148 |
149 | 150 |
151 | 152 |
153 |
154 | 155 | 156 | 157 |
158 | 159 | 160 | 161 |
162 | 163 | -------------------------------------------------------------------------------- /src/main/resources/templates/error/404.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 |

404 (NOT FOUND)

29 | 30 |

31 |
32 |

33 | 34 | 35 | 36 |
37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/templates/layout/footer.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 53 |
54 | 55 |
-------------------------------------------------------------------------------- /src/main/resources/templates/layout/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | <th:block th:text="${configuration.title}"></th:block><th:block th:if="${title != ''}" th:text="' : ' + ${title}"></th:block> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
71 | 72 | 73 | -------------------------------------------------------------------------------- /src/main/resources/templates/layout/other.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 21 | 22 | 23 |

24 | 25 | 26 | 27 |
28 | 29 | -------------------------------------------------------------------------------- /src/main/resources/templates/news-detail.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 |

17 | 18 | edit 19 | 20 | 21 |

22 | 23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 |

35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 | -------------------------------------------------------------------------------- /src/main/resources/templates/news-form.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
Saved!
16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 | error 24 |
25 |
26 |
27 | 28 |
29 | 30 | error 31 |
32 |
33 |
34 | 35 |
36 | 37 | error 38 |
39 |
40 |
41 | 42 |
43 | 44 | error 45 |
46 |
47 | 48 | 49 | 50 |
51 | 52 | 53 | 54 |
55 | 56 | -------------------------------------------------------------------------------- /src/main/resources/templates/news.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |

16 | 17 | Latest news from this website: 18 |

19 | 20 | 21 | 22 | 23 |

24 | 25 | edit 26 | 27 | 28 | 29 |

30 |
31 | 32 |
33 | 34 |

35 | 36 | Older items 37 | 38 | 39 | 40 | 41 |
42 | 43 | -------------------------------------------------------------------------------- /src/main/resources/templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 | Didn't find your favourite blog? Register and submit a missing blog. 20 | Otherwise you don't have to register. 21 |
22 | 23 |
Registration successfull!
24 | 25 |
26 | 27 |
28 | 29 | error 30 |
31 |
32 |
33 | 34 |
35 | 36 | error 37 |
38 |
39 |
40 | 41 |
42 | 43 | error 44 |
45 |
46 |
47 | 48 |
49 | 50 |
51 |
52 |
53 |
54 | 55 |
56 |
57 |
58 | 59 | 60 | 65 | 66 | 67 | 68 |
69 | 70 | -------------------------------------------------------------------------------- /src/main/resources/templates/user-detail.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |

16 | 17 |

18 | 19 | 24 | 25 | 26 | 29 | 30 | 31 |
32 |
33 | 34 |
35 |

Note: Only posts from last two months and max. 10 posts will be displayed.

36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 54 | 55 | 56 |
Item
46 | 47 | 48 | 49 |
50 | 51 |
52 | 53 |
57 |
58 |
59 | 60 | 61 | 62 |
63 | 64 | -------------------------------------------------------------------------------- /src/main/resources/templates/users.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 40 | 45 | 46 | 47 |
user namerolesoperations
32 | 33 | 35 | 36 | 37 |
38 |
39 |
41 | 44 |
48 | 49 | 50 | 51 |
52 | 53 | -------------------------------------------------------------------------------- /src/test/java/cz/jiripinkas/jba/service/AllTests.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import org.junit.runner.RunWith; 4 | import org.junit.runners.Suite; 5 | import org.junit.runners.Suite.SuiteClasses; 6 | 7 | @RunWith(Suite.class) 8 | @SuiteClasses({ BlogServiceTest.class, ItemServiceTest.class, RssServiceTest.class }) 9 | public class AllTests { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/cz/jiripinkas/jba/service/BlogServiceTest.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import java.util.Date; 4 | 5 | import org.junit.Before; 6 | import org.junit.Test; 7 | 8 | import static org.junit.Assert.*; 9 | 10 | public class BlogServiceTest { 11 | 12 | private BlogService blogService; 13 | 14 | @Before 15 | public void setUp() throws Exception { 16 | blogService = new BlogService(); 17 | } 18 | 19 | @Test 20 | public void testGetLastIndexDateMinutes() { 21 | blogService.setLastIndexedDateFinish(new Date()); 22 | assertEquals(blogService.getLastIndexDateMinutes(), 0); 23 | } 24 | 25 | @Test 26 | public void testGetLastIndexDateMinutesEmptyDateFinish() { 27 | assertEquals(blogService.getLastIndexDateMinutes(), 0); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/test/java/cz/jiripinkas/jba/service/ItemServiceTest.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | import java.util.GregorianCalendar; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | public class ItemServiceTest { 13 | 14 | private ItemService itemService; 15 | 16 | @Before 17 | public void setUp() throws Exception { 18 | itemService = new ItemService(); 19 | } 20 | 21 | @Test 22 | public void testIsTooOldOrYoung() { 23 | assertFalse(itemService.isTooOldOrYoung(new Date())); 24 | Calendar calendar1 = new GregorianCalendar(); 25 | calendar1.add(Calendar.MONTH, -5); 26 | assertTrue(itemService.isTooOldOrYoung(calendar1.getTime())); 27 | Calendar calendar2 = new GregorianCalendar(); 28 | calendar2.add(Calendar.DATE, 1); 29 | calendar2.add(Calendar.MINUTE, 1); 30 | assertTrue(itemService.isTooOldOrYoung(calendar2.getTime())); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/cz/jiripinkas/jba/service/scheduled/ScheduledTasksServiceTest.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.service.scheduled; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | import java.util.GregorianCalendar; 8 | 9 | import org.junit.Assert; 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | 13 | public class ScheduledTasksServiceTest { 14 | 15 | private ScheduledTasksService scheduledTasksService; 16 | 17 | @Before 18 | public void setup() { 19 | scheduledTasksService = new ScheduledTasksService(); 20 | } 21 | 22 | @Test 23 | public void shouldReturn_01_2015() throws ParseException { 24 | Date firstDayOfYear = new Date(new SimpleDateFormat("dd.MM.yyyy").parse("01.01.2015").getTime()); 25 | int[] weekAndYear = scheduledTasksService.getCurrentWeekAndYear(firstDayOfYear); 26 | Assert.assertEquals(1, weekAndYear[0]); 27 | Assert.assertEquals(2015, weekAndYear[1]); 28 | } 29 | 30 | @Test 31 | public void shouldReturn_02_2015() throws ParseException { 32 | Date firstDayOfYear = new Date(new SimpleDateFormat("dd.MM.yyyy").parse("08.01.2015").getTime()); 33 | int[] weekAndYear = scheduledTasksService.getCurrentWeekAndYear(firstDayOfYear); 34 | Assert.assertEquals(2, weekAndYear[0]); 35 | Assert.assertEquals(2015, weekAndYear[1]); 36 | } 37 | 38 | @Test 39 | public void shouldReturn_01_2016() throws ParseException { 40 | Date firstDayOfYear = new Date(new SimpleDateFormat("dd.MM.yyyy").parse("01.01.2016").getTime()); 41 | int[] weekAndYear = scheduledTasksService.getCurrentWeekAndYear(firstDayOfYear); 42 | Assert.assertEquals(1, weekAndYear[0]); 43 | Assert.assertEquals(2016, weekAndYear[1]); 44 | } 45 | 46 | @Test 47 | public void testReindexTimeoutPassed() { 48 | { 49 | Calendar calendar = new GregorianCalendar(); 50 | calendar.add(Calendar.DATE, -2); 51 | Assert.assertTrue(scheduledTasksService.reindexTimeoutPassed(calendar.getTime())); 52 | } 53 | { 54 | Calendar calendar = new GregorianCalendar(); 55 | calendar.add(Calendar.HOUR_OF_DAY, -1); 56 | Assert.assertFalse(scheduledTasksService.reindexTimeoutPassed(calendar.getTime())); 57 | } 58 | Assert.assertTrue(scheduledTasksService.reindexTimeoutPassed(null)); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/cz/jiripinkas/jba/util/MyUtilTest.java: -------------------------------------------------------------------------------- 1 | package cz.jiripinkas.jba.util; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import org.junit.Test; 6 | 7 | public class MyUtilTest { 8 | 9 | @Test 10 | public void testGetPublicName() throws Exception { 11 | assertEquals("tester (Test Test)", MyUtil.getPublicName("tester", "Test Test", false)); 12 | assertEquals("Test Test", MyUtil.getPublicName(null, "Test Test", false)); 13 | assertEquals("Test Test", MyUtil.getPublicName("", "Test Test", false)); 14 | assertEquals("loooooooooooooooo ... (Test Test)", MyUtil.getPublicName("looooooooooooooooooooooooooong nick", "Test Test", true)); 15 | assertEquals("looooooooooooooooooooooooooong nick (Test Test)", MyUtil.getPublicName("looooooooooooooooooooooooooong nick", "Test Test", false)); 16 | } 17 | 18 | } 19 | --------------------------------------------------------------------------------