From 9820abe11c0c037f50bb2f7ddbb0bd19646264dc Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Fri, 7 Apr 2017 10:29:52 +0300 Subject: juick-www: merge juick-spring-www i18n, drop thymeleaf --- .../src/main/java/com/juick/www/HelpService.java | 48 ---- .../src/main/java/com/juick/www/WebApp.java | 79 ------ .../www/configuration/WebAppConfiguration.java | 60 ----- .../juick/www/configuration/WebSecurityConfig.java | 70 ----- .../juick/www/configuration/WwwInitializer.java | 52 ---- .../www/configuration/WwwSecurityInitializer.java | 20 -- .../www/configuration/WwwServletConfiguration.java | 157 ----------- .../com/juick/www/controllers/ErrorController.java | 49 ---- .../com/juick/www/controllers/HelpController.java | 67 ----- .../com/juick/www/controllers/IndexController.java | 133 ---------- .../com/juick/www/controllers/PMController.java | 134 ---------- .../com/juick/www/controllers/PostController.java | 286 --------------------- .../juick/www/controllers/SettingsController.java | 278 -------------------- .../www/controllers/ShowMessageController.java | 169 ------------ .../com/juick/www/controllers/TagController.java | 112 -------- .../juick/www/controllers/ThreadController.java | 67 ----- .../juick/www/formatter/SpringDateFormatter.java | 44 ---- .../java/com/juick/www/helpers/QueryString.java | 14 - .../com/juick/www/helpers/QueryStringResolver.java | 31 --- .../main/java/com/juick/www/util/EncodeUtils.java | 10 - 20 files changed, 1880 deletions(-) delete mode 100644 juick-spring-www/src/main/java/com/juick/www/HelpService.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/WebApp.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/configuration/WebAppConfiguration.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/configuration/WwwInitializer.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/configuration/WwwSecurityInitializer.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/configuration/WwwServletConfiguration.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/ErrorController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/ShowMessageController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/controllers/ThreadController.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/formatter/SpringDateFormatter.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java delete mode 100644 juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java (limited to 'juick-spring-www/src/main/java/com/juick') diff --git a/juick-spring-www/src/main/java/com/juick/www/HelpService.java b/juick-spring-www/src/main/java/com/juick/www/HelpService.java deleted file mode 100644 index 8ece4cfb..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/HelpService.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.juick.www; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.cache.annotation.Cacheable; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.regex.Pattern; - -/** - * Created by aalexeev on 12/11/16. - */ -public class HelpService { - private static final Pattern LANG_PATTERN = Pattern.compile("[a-z]{2}"); - - private static final Pattern PAGE_PATTERN = Pattern.compile("[a-zA-Z0-9\\-_]+"); - - private final String helpPath; - - - public HelpService(String helpPath) { - this.helpPath = helpPath; - } - - @Cacheable("help") - public String getHelp(final String page, final String lang) { - if (canBePage(page) && canBeLang(lang)) { - String path = StringUtils.joinWith("/", helpPath, lang, page); - - try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path)) { - if (is != null) - return IOUtils.toString(is, StandardCharsets.UTF_8); - } catch (IOException e) { - } - } - return null; - } - - public boolean canBePage(final String anything) { - return anything != null && PAGE_PATTERN.matcher(anything).matches(); - } - - public boolean canBeLang(final String anything) { - return anything != null && LANG_PATTERN.matcher(anything).matches(); - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/WebApp.java b/juick-spring-www/src/main/java/com/juick/www/WebApp.java deleted file mode 100644 index 6b26ec03..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/WebApp.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.juick.www; - -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.math.NumberUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.env.Environment; -import rocks.xmpp.core.XmppException; -import rocks.xmpp.core.session.Extension; -import rocks.xmpp.core.session.XmppSessionConfiguration; -import rocks.xmpp.extensions.component.accept.ExternalComponent; - -import javax.annotation.PostConstruct; - -/** - * Created by vitalyster on 09.12.2016. - */ -public class WebApp implements AutoCloseable { - private static Logger logger = LoggerFactory.getLogger(WebApp.class); - - private ExternalComponent xmpp; - - public String tmpDir; - public String imgDir; - - private String xmppHost, xmppPassword, xmppJid; - private int xmppPort; - private boolean isXmppDisabled; - - - public WebApp(Environment conf) { - tmpDir = conf.getProperty("upload_tmp_dir", "/var/www/juick.com/i/tmp/"); - imgDir = conf.getProperty("img_path", "/var/www/juick.com/i/"); - isXmppDisabled = BooleanUtils.toBoolean(conf.getProperty("xmpp_disabled")); - xmppHost = conf.getProperty("xmpp_host", "localhost"); - xmppPort = NumberUtils.toInt(conf.getProperty("xmpp_port", "5347"), 5347); - xmppJid = conf.getProperty("xmpp_jid", "www.localhost"); - xmppPassword = conf.getProperty("xmpp_password"); - } - - @PostConstruct - public void init() { - if (!isXmppDisabled) { - setupXmppComponent(xmppHost, xmppPort, xmppJid, xmppPassword); - } - } - - @Override - public void close() { - try { - if (getXmpp() != null) - getXmpp().close(); - - logger.info("ExternalComponent on juick-www destroyed"); - } catch (Exception e) { - logger.warn("Exception occurs on juick-www destroy", e); - } - } - - public void setupXmppComponent(final String host, final int port, final String jid, final String password) { - XmppSessionConfiguration configuration = XmppSessionConfiguration.builder() - .extensions(Extension.of(com.juick.Message.class)) - .build(); - setXmpp(ExternalComponent.create(jid, password, configuration, host, port)); - try { - getXmpp().connect(); - } catch (XmppException e) { - logger.warn("xmpp extension", e); - } - } - - public ExternalComponent getXmpp() { - return xmpp; - } - - public void setXmpp(ExternalComponent xmpp) { - this.xmpp = xmpp; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/configuration/WebAppConfiguration.java b/juick-spring-www/src/main/java/com/juick/www/configuration/WebAppConfiguration.java deleted file mode 100644 index 4482dce1..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/configuration/WebAppConfiguration.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.juick.www.configuration; - -import com.juick.www.HelpService; -import com.juick.www.WebApp; -import org.apache.commons.lang3.CharEncoding; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.guava.GuavaCacheManager; -import org.springframework.cache.interceptor.KeyGenerator; -import org.springframework.cache.interceptor.SimpleKeyGenerator; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -import org.springframework.context.support.ResourceBundleMessageSource; -import org.springframework.core.env.Environment; - -import javax.annotation.Resource; - -/** - * Created by aalexeev on 11/22/16. - */ -@Configuration -@PropertySource("classpath:juick.conf") -@EnableCaching -public class WebAppConfiguration { - @Resource - private Environment env; - - @Bean - public ResourceBundleMessageSource messageSource() { - ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); - - messageSource.setBasenames("messages", "errors"); - messageSource.setDefaultEncoding(CharEncoding.UTF_8); - messageSource.setFallbackToSystemLocale(false); - messageSource.setUseCodeAsDefaultMessage(true); - - return messageSource; - } - - @Bean - public WebApp webApp() { - return new WebApp(env); - } - - @Bean - public GuavaCacheManager cacheManager() { - return new GuavaCacheManager("help"); - } - - @Bean - public HelpService helpService() { - return new HelpService("help"); - } - - @Bean - public KeyGenerator keyGenerator() { - // configure and return an implementation of Spring's KeyGenerator SPI - return new SimpleKeyGenerator(); - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java b/juick-spring-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java deleted file mode 100644 index 19485579..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.juick.www.configuration; - -import com.juick.server.security.entities.JuickUser; -import com.juick.service.UserService; -import com.juick.service.security.JuickUserDetailsService; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.PropertySource; -import org.springframework.core.env.Environment; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; -import org.springframework.security.core.userdetails.UserDetailsService; - -import javax.annotation.Resource; - -/** - * Created by aalexeev on 11/21/16. - */ -@EnableWebSecurity -@PropertySource("classpath:juick.conf") -public class WebSecurityConfig extends WebSecurityConfigurerAdapter { - @Resource - private Environment env; - @Resource - private UserService userService; - - @Bean("userDetailsService") - @Override - public UserDetailsService userDetailsServiceBean() throws Exception { - return super.userDetailsServiceBean(); - } - - @Override - public UserDetailsService userDetailsService() { - return new JuickUserDetailsService(userService); - } - - @Override - protected void configure(HttpSecurity http) throws Exception { - http - .authorizeRequests() - .antMatchers("/settings", "/pm/**").authenticated() - .anyRequest().permitAll() - .and() - .anonymous().principal(JuickUser.ANONYMOUS_USER).authorities(JuickUser.ANONYMOUS_AUTHORITY) - .and() - .sessionManagement().invalidSessionUrl("/") - .and() - .logout().invalidateHttpSession(true).logoutUrl("/logout").logoutSuccessUrl("/") - .and() - .formLogin() - .loginPage("/login") - .permitAll() - .defaultSuccessUrl("/") - .loginProcessingUrl("/do_login") - .usernameParameter("j_username") - .passwordParameter("j_password") - .failureUrl("/login-error") - .and() - .rememberMe() - .tokenValiditySeconds(6 * 30 * 24 * 3600) - .alwaysRemember(true) - //.useSecureCookie(true) // TODO Enable if https is supports - .rememberMeCookieDomain(env.getProperty("web_domain", "juick.com")) - .userDetailsService(userDetailsService()) - .key(env.getProperty("auth_remember_me_key")) - .and() - .csrf().disable(); - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/configuration/WwwInitializer.java b/juick-spring-www/src/main/java/com/juick/www/configuration/WwwInitializer.java deleted file mode 100644 index 33687983..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/configuration/WwwInitializer.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.juick.www.configuration; - -import com.juick.configuration.DataConfiguration; -import com.juick.configuration.SearchConfiguration; -import org.apache.commons.lang3.CharEncoding; -import org.springframework.web.filter.CharacterEncodingFilter; -import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; - -import javax.servlet.FilterRegistration; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -/** - * Created by aalexeev on 11/20/16. - */ -public class WwwInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { - - @Override - protected Class[] getRootConfigClasses() { - return new Class[]{ - WebAppConfiguration.class, - DataConfiguration.class, - SearchConfiguration.class, - WebSecurityConfig.class}; - } - - @Override - protected Class[] getServletConfigClasses() { - return new Class[]{WwwServletConfiguration.class}; - } - - @Override - protected String[] getServletMappings() { - return new String[]{"/"}; - } - - @Override - protected String getServletName() { - return "WWW-spring dispatcher servlet"; - } - - @Override - public void onStartup(ServletContext servletContext) throws ServletException { - super.onStartup(servletContext); - - FilterRegistration.Dynamic registration = servletContext.addFilter( - "encodingFilter", new CharacterEncodingFilter(CharEncoding.UTF_8, true)); - - registration.addMappingForUrlPatterns(null, true, "/*"); - } -} - diff --git a/juick-spring-www/src/main/java/com/juick/www/configuration/WwwSecurityInitializer.java b/juick-spring-www/src/main/java/com/juick/www/configuration/WwwSecurityInitializer.java deleted file mode 100644 index 0ea8c907..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/configuration/WwwSecurityInitializer.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.juick.www.configuration; - -/** - * Created by vitalyster on 25.11.2016. - */ - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; - -import javax.servlet.ServletContext; - -public class WwwSecurityInitializer extends AbstractSecurityWebApplicationInitializer { - private final Logger logger = LoggerFactory.getLogger(getClass()); - - @Override - protected void afterSpringSecurityFilterChain(ServletContext servletContext) { - logger.info("SpringSecurityFilterChain initialized"); - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/configuration/WwwServletConfiguration.java b/juick-spring-www/src/main/java/com/juick/www/configuration/WwwServletConfiguration.java deleted file mode 100644 index 5cd251e6..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/configuration/WwwServletConfiguration.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.juick.www.configuration; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; -import com.juick.www.formatter.SpringDateFormatter; -import nz.net.ultraq.thymeleaf.LayoutDialect; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.CharEncoding; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.PropertySource; -import org.springframework.core.env.Environment; -import org.springframework.format.FormatterRegistry; -import org.springframework.http.CacheControl; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import org.springframework.web.multipart.MultipartResolver; -import org.springframework.web.multipart.commons.CommonsMultipartResolver; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; -import org.springframework.web.servlet.resource.PathResourceResolver; -import org.thymeleaf.extras.springsecurity4.dialect.SpringSecurityDialect; -import org.thymeleaf.spring4.SpringTemplateEngine; -import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver; -import org.thymeleaf.spring4.view.ThymeleafViewResolver; -import org.thymeleaf.templatemode.TemplateMode; - -import javax.annotation.Resource; -import java.util.List; -import java.util.concurrent.TimeUnit; - -/** - * Created by vitalyster on 28.06.2016. - */ -@Configuration -@ComponentScan(basePackages = {"com.juick.www.controllers"}) -@PropertySource("classpath:juick.conf") -public class WwwServletConfiguration extends WebMvcConfigurationSupport { - @Resource - private Environment env; - - @Bean - public SpringResourceTemplateResolver templateResolver() { - // SpringResourceTemplateResolver automatically integrates with Spring's own - // resource resolution infrastructure, which is highly recommended. - SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); - templateResolver.setApplicationContext(getApplicationContext()); - templateResolver.setPrefix("/WEB-INF/templates/"); - templateResolver.setSuffix(".html"); - // HTML is the default value, added here for the sake of clarity. - templateResolver.setTemplateMode(TemplateMode.HTML); - // Template cache is true by default. Set to false if you want - // templates to be automatically updated when modified. - templateResolver.setCacheable(true); - - templateResolver.setCharacterEncoding(CharEncoding.UTF_8); - return templateResolver; - } - - @Bean - public SpringTemplateEngine templateEngine() { - // SpringTemplateEngine automatically applies SpringStandardDialect and - // enables Spring's own MessageSource message resolution mechanisms. - SpringTemplateEngine templateEngine = new SpringTemplateEngine(); - templateEngine.setTemplateResolver(templateResolver()); - // Enabling the SpringEL compiler with Spring 4.2.4 or newer can - // speed up execution in most scenarios, but might be incompatible - // with specific cases when expressions in one template are reused - // across different data types, so this flag is "false" by default - // for safer backwards compatibility. - templateEngine.setEnableSpringELCompiler(true); - // Thymeleaf Layout Dialect - templateEngine.addDialect(new LayoutDialect()); - // Thymeleaf Spring Security integration dialect - templateEngine.addDialect(new SpringSecurityDialect()); - - return templateEngine; - } - - @Bean - public ThymeleafViewResolver viewResolver() { - ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); - viewResolver.setTemplateEngine(templateEngine()); - viewResolver.setCharacterEncoding(CharEncoding.UTF_8); - - viewResolver.addStaticVariable( - "showSape", BooleanUtils.toBoolean(env.getProperty("template.showSape", "true"))); - viewResolver.addStaticVariable( - "showAdv", BooleanUtils.toBoolean(env.getProperty("template.showAdv", "true"))); - viewResolver.addStaticVariable( - "showSponsors", BooleanUtils.toBoolean(env.getProperty("template.showSponsors", "false"))); - - return viewResolver; - } - - @Override - protected void configureMessageConverters(List> converters) { - Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder() - .serializationInclusion(JsonInclude.Include.NON_DEFAULT) - .serializationInclusion(JsonInclude.Include.NON_NULL) - .serializationInclusion(JsonInclude.Include.NON_ABSENT) - .serializationInclusion(JsonInclude.Include.NON_EMPTY); - - MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build()); - converter.getObjectMapper().registerModule(new Jdk8Module()); - converters.add(converter); - - super.configureMessageConverters(converters); - } - - @Override - protected void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.setOrder(0); - registry.addResourceHandler( - "/scripts.js*", - "/style.css*", - "/*.png", - "/favicon.ico") - .addResourceLocations("/") - .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)) - .resourceChain(true) - .addResolver(new PathResourceResolver()); - - registry.addResourceHandler("/static/**") - .addResourceLocations("/static/") - .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS)); - } - - @Override - public RequestMappingHandlerMapping requestMappingHandlerMapping() { - RequestMappingHandlerMapping result = super.requestMappingHandlerMapping(); - - result.setOrder(1); - - return result; - } - - @Override - public void addFormatters(final FormatterRegistry registry) { - registry.addFormatter(dateFormatter()); - } - - @Bean - public SpringDateFormatter dateFormatter() { - return new SpringDateFormatter(); - } - - @Bean - public MultipartResolver multipartResolver() { - CommonsMultipartResolver resolver = new CommonsMultipartResolver(); - resolver.setMaxUploadSize(10000000); - return resolver; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/ErrorController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/ErrorController.java deleted file mode 100644 index 57a34076..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/ErrorController.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.server.util.HttpBadRequestException; -import com.juick.server.util.HttpForbiddenException; -import com.juick.server.util.HttpNotFoundException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.http.HttpStatus; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseStatus; - -/** - * Created by aalexeev on 12/12/16. - */ -@ControllerAdvice -public class ErrorController { - private static Logger logger = LoggerFactory.getLogger(ErrorController.class); - - @ExceptionHandler(HttpBadRequestException.class) - @ResponseStatus(value = HttpStatus.BAD_REQUEST) - public String badRequest() { - return "views/error"; - } - - @ExceptionHandler(HttpForbiddenException.class) - @ResponseStatus(value = HttpStatus.FORBIDDEN) - public String forbidden() { - return "views/error"; - } - - @ExceptionHandler(HttpNotFoundException.class) - @ResponseStatus(value = HttpStatus.NOT_FOUND) - public String notFound() { - return "views/error"; - } - - @ExceptionHandler(Throwable.class) - @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) - public String exception(final Throwable throwable, final Model model) { - logger.error("Exception during execution of SpringSecurity application", throwable); - - String errorMessage = (throwable != null ? throwable.getMessage() : "Unknown error"); - model.addAttribute("errorMessage", errorMessage); - - return "views/error"; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java deleted file mode 100644 index 3387f821..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/HelpController.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.server.util.HttpNotFoundException; -import com.juick.util.UserUtils; -import com.juick.www.HelpService; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; - -import javax.inject.Inject; -import java.io.IOException; -import java.net.URISyntaxException; -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; - -/** - * Created by aalexeev on 11/21/16. - */ -@Controller -public class HelpController { - @Inject - private HelpService helpService; - - @RequestMapping({"/help", "/help/{langOrPage}", "/help/{lang}/{page}"}) - public String showHelp( - Locale locale, - @PathVariable("lang") Optional langParam, - @PathVariable("page") Optional pageParam, - @PathVariable("langOrPage") Optional langOrPageParam, - Model model) throws IOException, URISyntaxException { - - String page = pageParam.orElse("index"); - String lang = langParam.orElse(locale.getLanguage()); - - String navigation = null; - - if (langOrPageParam.isPresent()) { - String langOrPage = langOrPageParam.get(); - - if (helpService.canBeLang(langOrPage)) { - navigation = helpService.getHelp("navigation", langOrPage); - if (navigation != null) - lang = langOrPage; - } - - if (navigation == null && helpService.canBePage(langOrPage)) - page = langOrPage; - } - - String content = helpService.getHelp(page, lang); - if (content == null && !Objects.equals("index", page)) - content = helpService.getHelp("index", lang); - - if (navigation == null) - navigation = helpService.getHelp("navigation", lang); - - if (content == null || navigation == null) - throw new HttpNotFoundException(); - - model.addAttribute("help_nav", navigation); - model.addAttribute("help_data", content); - - return "views/help"; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java deleted file mode 100644 index 87540795..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/IndexController.java +++ /dev/null @@ -1,133 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.Message; -import com.juick.User; -import com.juick.service.MessagesService; -import com.juick.service.TagService; -import com.juick.service.UserService; -import com.juick.util.UserUtils; -import com.juick.www.util.EncodeUtils; -import org.apache.commons.lang3.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.context.MessageSource; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.inject.Inject; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * Created by aalexeev on 11/21/16. - */ -@Controller -public class IndexController { - @Inject - private MessageSource messageSource; - @Inject - private UserService userService; - @Inject - private MessagesService messagesService; - @Inject - private TagService tagService; - - @RequestMapping(value = "/", method = RequestMethod.GET) - public String indexPage( - @RequestParam("show") Optional paramShow, - @RequestParam("tag") Optional paramTagStr, - @RequestParam(value = "before") Optional paramBefore, - @RequestParam(value = "search", required = false) String paramSearch, - ModelMap model) throws IOException { - - int before = paramBefore.orElse(0); - String tag = paramTagStr.orElse(StringUtils.EMPTY); - - if (StringUtils.isNotEmpty(tag)) { - StringBuilder builder = new StringBuilder(); - builder.append("redirect:").append("/tag/").append(tag); - if (before > 0) - builder.append("?before=").append(before); - return builder.toString(); - } - - if (StringUtils.isNotEmpty(paramSearch) && paramSearch.length() > 64) - paramSearch = StringUtils.EMPTY; - - User visitor = UserUtils.getCurrentUser(); - - String title = StringUtils.EMPTY; - - List mids = new ArrayList<>(); - - if (StringUtils.isNotEmpty(paramSearch)) { - title = "Поиск: " + StringEscapeUtils.escapeHtml4(paramSearch); - mids = messagesService.getSearch(EncodeUtils.encodeSphinx(paramSearch), - before); - } else if (!paramShow.isPresent()) { - mids = messagesService.getPopular(visitor.getUid(), before); - } else if (paramShow.get().equals("top")) { - return "redirect:/"; - } else if (paramShow.get().equals("my") && visitor.getUid() > 0) { - title = "Моя лента"; - mids = messagesService.getMyFeed(visitor.getUid(), before); - } else if (paramShow.get().equals("private") && visitor.getUid() > 0) { - title = "Приватные"; - mids = messagesService.getPrivate(visitor.getUid(), before); - } else if (paramShow.get().equals("discuss") && visitor.getUid() > 0) { - title = "Обсуждения"; - mids = messagesService.getDiscussions(visitor.getUid(), before); - } else if (paramShow.get().equals("recommended") && visitor.getUid() > 0) { - title = "Рекомендации"; - mids = messagesService.getRecommended(visitor.getUid(), before); - } else if (paramShow.get().equals("photos")) { - title = "Фотографии"; - mids = messagesService.getPhotos(visitor.getUid(), before); - } else if (paramShow.get().equals("all")) { - title = "Все сообщения"; - mids = messagesService.getAll(visitor.getUid(), before); - } - model.addAttribute("title", title); - model.addAttribute("tags", tagService.getPopularTags()); - List msgs = messagesService.getMessages(mids); - List blUIDs = userService.checkBL(visitor.getUid(), - msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList())); - model.addAttribute("msgs", - msgs.stream().map(msg -> { - msg.ReadOnly |= blUIDs.contains(msg.getUser().getUid()); - if (msg.ReadOnly) { - msg.ReadOnly = visitor.getUid() != msg.getUser().getUid(); - } - return msg; - }).collect(Collectors.toList()) - ); - if (mids.size() >= 20) { - String nextpage = "?before=" + mids.get(mids.size() - 1); - if (paramShow.isPresent()) { - nextpage += "&show=" + paramShow.get(); - } - if (StringUtils.isNotEmpty(paramSearch)) { - nextpage += "&search=" + paramSearch; - } - model.addAttribute("nextpage", nextpage); - } - return "views/index"; - } - - @RequestMapping(value = "/login", method = RequestMethod.GET) - public String getLoginForm() { - return "views/login"; - } - - @RequestMapping(value = "/login-error", method = RequestMethod.GET) - public String getLoginErrorForm(Model model) { - model.addAttribute("loginError", true); - return "views/login"; - } -} \ No newline at end of file diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java deleted file mode 100644 index f590fc7c..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/PMController.java +++ /dev/null @@ -1,134 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.Message; -import com.juick.User; -import com.juick.server.util.HttpBadRequestException; -import com.juick.server.util.HttpForbiddenException; -import com.juick.service.PMQueriesService; -import com.juick.service.TagService; -import com.juick.service.UserService; -import com.juick.util.MessageUtils; -import com.juick.util.UserUtils; -import com.juick.util.WebUtils; -import com.juick.www.WebApp; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import rocks.xmpp.addr.Jid; - -import javax.inject.Inject; -import java.util.List; - -/** - * Created by vitalyster on 09.12.2016. - */ -@Controller -public class PMController { - private static final Logger logger = LoggerFactory.getLogger(PMController.class); - - @Inject - PMQueriesService pmQueriesService; - @Inject - UserService userService; - @Inject - TagService tagService; - @Inject - WebApp webApp; - - @RequestMapping("/pm/inbox") - public String doGetInbox(ModelMap context) { - User visitor = UserUtils.getCurrentUser(); - - String title = "PM: Inbox"; - List msgs = pmQueriesService.getLastPMInbox(visitor.getUid()); - - msgs.forEach(m -> m.setText(MessageUtils.formatMessage(m.getText()))); - - context.put("title", title); - context.put("msgs", msgs); - context.put("tags", tagService.getPopularTags()); - - return "views/pm_inbox"; - } - - @RequestMapping(value = "/pm/sent", method = RequestMethod.GET) - public String doGetSent( - @RequestParam String uname, - ModelMap context) { - String title = "PM: Sent"; - User visitor = UserUtils.getCurrentUser(); - List msgs = pmQueriesService.getLastPMSent(visitor.getUid()); - - if (WebUtils.isNotUserName(uname)) { - uname = StringUtils.EMPTY; - } - context.put("title", title); - context.put("msgs", msgs); - context.put("tags", tagService.getPopularTags()); - context.put("uname", uname); - return "views/pm_sent"; - } - - @RequestMapping(value = "/pm/send", method = RequestMethod.POST) - public String doPostPM( - @RequestParam String uname, - @RequestParam String body, - ModelMap context) { - User visitor = UserUtils.getCurrentUser(); - if (uname.startsWith("@")) { - uname = uname.substring(1); - } - int uid = 0; - if (WebUtils.isUserName(uname)) { - uid = userService.getUIDbyName(uname); - } - - if (uid == 0 || body == null || body.length() < 1 || body.length() > 10240) { - throw new HttpBadRequestException(); - } - - if (userService.isInBLAny(uid, visitor.getUid())) { - throw new HttpForbiddenException(); - } - - if (pmQueriesService.createPM(visitor.getUid(), uid, body)) { - if (webApp.getXmpp() != null) { - rocks.xmpp.core.stanza.model.Message msg = new rocks.xmpp.core.stanza.model.Message(); - msg.setFrom(Jid.of("juick@juick.com")); - msg.setTo(Jid.of(String.format("%d@push.juick.com", uid))); - com.juick.Message jmsg = new com.juick.Message(); - jmsg.setUser(visitor); - jmsg.setText(body); - msg.addExtension(jmsg); - webApp.getXmpp().send(msg); - - msg.setTo(Jid.of(String.format("%d@ws.juick.com", uid))); - webApp.getXmpp().send(msg); - - List jids = userService.getJIDsbyUID(uid); - for (String jid : jids) { - rocks.xmpp.core.stanza.model.Message mm = new rocks.xmpp.core.stanza.model.Message(); - mm.setTo(Jid.of(jid)); - mm.setType(rocks.xmpp.core.stanza.model.Message.Type.CHAT); - if (pmQueriesService.havePMinRoster(visitor.getUid(), jid)) { - mm.setFrom(Jid.of(jmsg.getUser().getName(), "juick.com", "Juick")); - mm.setBody(body); - } else { - mm.setFrom(Jid.of("juick", "juick.com", "Juick")); - mm.setBody("Private message from @" + jmsg.getUser().getName() + ":\n" + body); - } - webApp.getXmpp().send(mm); - } - } else { - logger.warn("XMPP unavailable"); - } - return "redirect:/pm/sent"; - } - throw new HttpBadRequestException(); - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java deleted file mode 100644 index 8ad06402..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/PostController.java +++ /dev/null @@ -1,286 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.Tag; -import com.juick.User; -import com.juick.server.util.HttpBadRequestException; -import com.juick.server.util.HttpForbiddenException; -import com.juick.server.util.HttpNotFoundException; -import com.juick.server.util.HttpUtils; -import com.juick.service.MessagesService; -import com.juick.service.SubscriptionService; -import com.juick.service.TagService; -import com.juick.service.UserService; -import com.juick.util.UserUtils; -import com.juick.www.WebApp; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.CharEncoding; -import org.apache.commons.lang3.StringUtils; -import org.imgscalr.Scalr; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.multipart.MultipartFile; -import rocks.xmpp.addr.Jid; -import rocks.xmpp.core.stanza.model.Message; -import rocks.xmpp.extensions.nick.model.Nickname; -import rocks.xmpp.extensions.oob.model.x.OobX; - -import javax.imageio.ImageIO; -import javax.inject.Inject; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.List; - -/** - * Created by vitalyster on 20.12.2016. - */ -@Controller -public class PostController { - - private static final Logger logger = LoggerFactory.getLogger(PostController.class); - - @Inject - MessagesService messagesService; - @Inject - UserService userService; - @Inject - SubscriptionService subscriptionService; - @Inject - TagService tagService; - @Inject - WebApp webApp; - @Inject - Environment env; - - @RequestMapping(value = "/post", method = RequestMethod.POST) - public String doPost( - @RequestParam(required = false, value = "tags") String tagsStr, - @RequestParam String body, - @RequestParam(required = false) String img, - @RequestParam(required = false) MultipartFile attach, - ModelMap modelMap - ) throws IOException { - body = body.replace("\r", StringUtils.EMPTY); - - List tags = tagService.fromString(tagsStr, true); - - String attachmentFName = HttpUtils.receiveMultiPartFile(attach, env.getProperty("upload_tmp_dir", - "/var/www/juick.com/i/tmp/")); - - if (StringUtils.isBlank(attachmentFName) && img != null && img.length() > 10) { - try { - URL imgUrl = new URL(img); - attachmentFName = HttpUtils.downloadImage(imgUrl); - } catch (Exception e) { - logger.error("DOWNLOAD ERROR", e); - throw new HttpBadRequestException(); - } - } - - User visitor = UserUtils.getCurrentUser(); - - String attachmentType = StringUtils.isNotEmpty(attachmentFName) ? attachmentFName.substring(attachmentFName.length() - 3) : null; - int mid = messagesService.createMessage(visitor.getUid(), body, attachmentType, tags); - subscriptionService.subscribeMessage(mid, visitor.getUid()); - - Message xmsg = new Message(); - xmsg.setFrom(Jid.of("juick@juick.com")); - xmsg.setType(Message.Type.CHAT); - xmsg.setThread("juick-" + mid); - com.juick.Message jmsg = messagesService.getMessage(mid); - xmsg.addExtension(jmsg); - xmsg.addExtension(new Nickname("@" + jmsg.getUser().getName())); - - if (StringUtils.isNotEmpty(attachmentFName)) { - String fname = mid + "." + attachmentType; - String attachmentURL = "http://i.juick.com/photos-1024/" + fname; - - Path origName = Paths.get(webApp.imgDir, "p", fname); - Files.move(Paths.get(webApp.tmpDir, attachmentFName), origName); - BufferedImage originalImage = ImageIO.read(origName.toFile()); - ImageIO.write(Scalr.resize(originalImage, 1024), - FilenameUtils.getExtension(origName.toString()), - Paths.get(webApp.imgDir, "photos-1024", fname).toFile()); - ImageIO.write(Scalr.resize(originalImage, 512), - FilenameUtils.getExtension(origName.toString()), - Paths.get(webApp.imgDir, "photos-512", fname).toFile()); - ImageIO.write(Scalr.resize(originalImage, 160), - FilenameUtils.getExtension(origName.toString()), - Paths.get(webApp.imgDir, "ps", fname).toFile()); - - body = attachmentURL + "\n" + body; - try { - xmsg.addExtension(new OobX(new URI(attachmentURL))); - } catch (URISyntaxException e) { - logger.warn("invalid uri: {} exception {}", attachmentURL, e); - } - } - if (webApp.getXmpp() != null) { - - xmsg.setBody("@" + jmsg.getUser().getName() + ":" + jmsg.getTagsString() + "\n" + body + "\n\n#" + mid + " http://juick.com/" + mid); - - xmsg.setTo(Jid.of("juick@s2s.juick.com")); - webApp.getXmpp().send(xmsg); - - xmsg.setTo(Jid.of("juick@ws.juick.com")); - webApp.getXmpp().send(xmsg); - - xmsg.setTo(Jid.of("juick@push.juick.com")); - webApp.getXmpp().send(xmsg); - - xmsg.setTo(Jid.of("jubo@nologin.ru")); - webApp.getXmpp().send(xmsg); - } else { - logger.warn("XMPP unavailable"); - } - - String hashtags = StringUtils.EMPTY; - String tagscomma = StringUtils.EMPTY; - for (int i = 0; i < jmsg.getTags().size(); i++) { - if (i > 0) { - hashtags += " "; - tagscomma += ","; - } - hashtags += "#" + jmsg.getTags().get(i); - tagscomma += jmsg.getTags().get(i); - } - - String url = URLEncoder.encode("http://juick.com/" + mid, CharEncoding.UTF_8); - String sharetwi = hashtags + " " + body; - if (sharetwi.length() > 115) { - sharetwi = sharetwi.substring(0, 114) + "…"; - } - sharetwi += " http://juick.com/" + mid; - String sharelj = URLEncoder.encode(body + "\n", CharEncoding.UTF_8) + url; - - modelMap.put("title", "Сообщение опубликовано"); - modelMap.put("url", url); - modelMap.put("sharetwi", URLEncoder.encode(sharetwi, CharEncoding.UTF_8)); - modelMap.put("sharelj", sharelj); - modelMap.put("mid", mid); - - return "views/posted"; - } - - @RequestMapping(value = "/comment", method = RequestMethod.POST) - public String doComment( - @RequestParam(defaultValue = "0") int mid, - @RequestParam(required = false, defaultValue = "0") int rid, - @RequestParam String body, - @RequestParam(required = false) String img, - @RequestParam(required = false) MultipartFile attach) throws IOException { - com.juick.Message msg = messagesService.getMessage(mid); - if (msg == null) { - throw new HttpNotFoundException(); - } - - com.juick.Message reply = null; - if (rid > 0) { - reply = messagesService.getReply(mid, rid); - if (reply == null) { - throw new HttpNotFoundException(); - } - } - - if (body.length() < 1 || body.length() > 4096) { - throw new HttpBadRequestException(); - } - body = body.replace("\r", StringUtils.EMPTY); - - User visitor = UserUtils.getCurrentUser(); - - if ((msg.ReadOnly && msg.getUser().getUid() != visitor.getUid()) - || userService.isInBLAny(msg.getUser().getUid(), visitor.getUid()) - || (reply != null && userService.isInBLAny(reply.getUser().getUid(), visitor.getUid()))) { - throw new HttpForbiddenException(); - } - - String attachmentFName = HttpUtils.receiveMultiPartFile(attach, env.getProperty("upload_tmp_dir", - "/var/www/juick.com/i/tmp/")); - - if (StringUtils.isBlank(attachmentFName) && img != null && img.length() > 10) { - try { - URL imgUrl = new URL(img); - attachmentFName = HttpUtils.downloadImage(imgUrl); - } catch (Exception e) { - logger.error("DOWNLOAD ERROR", e); - throw new HttpBadRequestException(); - } - } - - String attachmentType = StringUtils.isNotEmpty(attachmentFName) ? attachmentFName.substring(attachmentFName.length() - 3) : null; - int ridnew = messagesService.createReply(mid, rid, visitor.getUid(), body, attachmentType); - subscriptionService.subscribeMessage(mid, visitor.getUid()); - - com.juick.Message jmsg = messagesService.getReply(mid, ridnew); - - Message xmsg = new Message(); - xmsg.setFrom(Jid.of("juick@juick.com")); - xmsg.setType(Message.Type.CHAT); - xmsg.setThread("juick-" + mid); - - xmsg.addExtension(jmsg); - - String quote = reply != null ? reply.getText() : msg.getText(); - if (quote.length() >= 50) { - quote = quote.substring(0, 47) + "..."; - } - xmsg.addExtension(new Nickname("@" + jmsg.getUser().getName())); - - if (StringUtils.isNotEmpty(attachmentFName)) { - String fname = mid + "-" + ridnew + "." + attachmentType; - String attachmentURL = "http://i.juick.com/photos-1024/" + fname; - - Path origName = Paths.get(webApp.imgDir, "p", fname); - Files.move(Paths.get(webApp.tmpDir, attachmentFName), origName); - BufferedImage originalImage = ImageIO.read(origName.toFile()); - ImageIO.write(Scalr.resize(originalImage, 1024), - FilenameUtils.getExtension(origName.toString()), - Paths.get(webApp.imgDir, "photos-1024", fname).toFile()); - ImageIO.write(Scalr.resize(originalImage, 512), - FilenameUtils.getExtension(origName.toString()), - Paths.get(webApp.imgDir, "photos-512", fname).toFile()); - ImageIO.write(Scalr.resize(originalImage, 160), - FilenameUtils.getExtension(origName.toString()), - Paths.get(webApp.imgDir, "ps", fname).toFile()); - - body = attachmentURL + "\n" + body; - try { - xmsg.addExtension(new OobX(new URI(attachmentURL))); - } catch (URISyntaxException e) { - logger.warn("invalid uri: {}, exception {}", attachmentURL, e); - } - } - - if (webApp.getXmpp() != null) { - - xmsg.setBody("Reply by @" + jmsg.getUser().getName() + ":\n>" + quote + "\n" + body + "\n\n#" + - mid + "/" + ridnew + " http://juick.com/" + mid + "#" + ridnew); - - xmsg.setTo(Jid.of("juick@s2s.juick.com")); - webApp.getXmpp().send(xmsg); - - xmsg.setTo(Jid.of("juick@ws.juick.com")); - webApp.getXmpp().send(xmsg); - - xmsg.setTo(Jid.of("juick@push.juick.com")); - webApp.getXmpp().send(xmsg); - } else { - logger.warn("XMPP unavailable"); - } - - return "redirect:/" + msg.getUser().getName() + "/" + mid + "#" + ridnew; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java deleted file mode 100644 index 58668dc1..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/SettingsController.java +++ /dev/null @@ -1,278 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.User; -import com.juick.server.helpers.NotifyOpts; -import com.juick.server.helpers.UserInfo; -import com.juick.server.util.HttpBadRequestException; -import com.juick.server.util.HttpForbiddenException; -import com.juick.server.util.HttpUtils; -import com.juick.service.*; -import com.juick.util.UserUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; -import org.imgscalr.Scalr; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.env.Environment; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.multipart.MultipartFile; - -import javax.imageio.ImageIO; -import javax.inject.Inject; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.Transport; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -/** - * Created by aalexeev on 11/21/16. - */ -@Controller -public class SettingsController { - private static final Logger logger = LoggerFactory.getLogger(SettingsController.class); - @Inject - UserService userService; - @Inject - TagService tagService; - @Inject - CrosspostService crosspostService; - @Inject - SubscriptionService subscriptionService; - @Inject - EmailService emailService; - @Inject - TelegramService telegramService; - @Inject - Environment env; - - @RequestMapping(value = "settings", method = RequestMethod.GET) - public String showSettings( - @RequestParam(required = false) String page, - @RequestParam(required = false) String code, - ModelMap context) { - User visitor = UserUtils.getCurrentUser(); - if (visitor.getUid() == 0) { - return "redirect:/login"; - } - List pages = Arrays.asList("main", "password", "about", "auth-email", "privacy"); - if (StringUtils.isEmpty(page) || !pages.contains(page)) { - page = "main"; - } - context.put("title", "Настройки"); - context.put("tags", tagService.getPopularTags()); - context.put("auths", userService.getAuthCodes(visitor)); - context.put("eopts", userService.getEmailOpts(visitor)); - context.put("ehash", userService.getEmailHash(visitor)); - context.put("emails", userService.getEmails(visitor)); - context.put("jids", userService.getAllJIDs(visitor)); - List hours = IntStream.rangeClosed(0, 23).boxed() - .map(i -> StringUtils.leftPad(String.format("%d", i), 2, "0")).collect(Collectors.toList()); - context.put("hours", hours); - context.put("fbstatus", crosspostService.getFbCrossPostStatus(visitor.getUid())); - context.put("twitter_name", crosspostService.getTwitterName(visitor.getUid())); - context.put("telegram_name", crosspostService.getTelegramName(visitor.getUid())); - context.put("notify_options", subscriptionService.getNotifyOptions(visitor)); - context.put("userinfo", userService.getUserInfo(visitor)); - if (page.equals("auth-email")) { - String response = emailService.verifyAddressByCode(visitor.getUid(), code) ? - "OK!" : "Sorry, code unknown."; - context.put("result", response); - } - return String.format("views/settings_%s", page); - } - @RequestMapping(value = "/settings", method = RequestMethod.POST) - protected String doPost( - HttpServletResponse response, - @RequestParam String page, - @RequestParam(required = false) String password, - @RequestParam(required = false) String jnotify, - @RequestParam(required = false) String subscr_notify, - @RequestParam(required = false) String recomm, - @RequestParam(required = false) String fullname, - @RequestParam(required = false) String country, - @RequestParam(required = false) String url, - @RequestParam(required = false) String descr, - @RequestParam(required = false) MultipartFile avatar, - @RequestParam(required = false) String account, - @RequestParam(required = false) String time, - ModelMap context) throws IOException { - User visitor = UserUtils.getCurrentUser(); - if (visitor.getUid() == 0) { - throw new HttpForbiddenException(); - } - List pages = Arrays.asList("main", "password", "about", "email", "email-add", "email-del", - "email-subscr", "auth-email", "privacy", "jid-del", "twitter-del", "telegram-del", "facebook-disable", - "facebook-enable", "vk-del"); - if (StringUtils.isEmpty(page) || !pages.contains(page)) { - throw new HttpBadRequestException(); - } - String result = StringUtils.EMPTY; - switch (page) { - case "password": - if (userService.updatePassword(visitor, password)) { - result = "

Password has been changed.

"; - String hash = userService.getHashByUID(visitor.getUid()); - Cookie c = new Cookie("hash", hash); - c.setMaxAge(365 * 24 * 60 * 60); - // FIXME: use spring-security - response.addCookie(c); - } - break; - case "main": - NotifyOpts opts = new NotifyOpts(); - opts.setRepliesEnabled(StringUtils.isNotEmpty(jnotify)); - opts.setSubscriptionsEnabled(StringUtils.isNotEmpty(subscr_notify)); - opts.setRecommendationsEnabled(StringUtils.isNotEmpty(recomm)); - if (subscriptionService.setNotifyOptions(visitor, opts)) { - result = "

Notification options has been updated

"; - } - break; - case "about": - UserInfo info = new UserInfo(); - info.setFullName(fullname); - info.setCountry(country); - info.setUrl(url); - info.setDescription(descr); - String imgPath = env.getProperty("img_path", "/var/www/juick.com/i/"); - String tmpDir = env.getProperty("upload_tmp_dir", - "/var/www/juick.com/i/tmp/"); - String avatarTmpPath = HttpUtils.receiveMultiPartFile(avatar, tmpDir); - if (StringUtils.isNotEmpty(avatarTmpPath)) { - String originalExtension = FilenameUtils.getExtension(avatarTmpPath); - String originalName = String.format("%s.%s", visitor.getUid(), originalExtension); - String targetName = String.format("%s.png", visitor.getUid()); - Path ao = Paths.get(imgPath, "ao", originalName); - Path a = Paths.get(imgPath, "a", targetName); - Path as = Paths.get(imgPath, "as", targetName); - Files.move(Paths.get(tmpDir, avatarTmpPath), ao, StandardCopyOption.REPLACE_EXISTING); - BufferedImage originalImage = ImageIO.read(ao.toFile()); - ImageIO.write(Scalr.resize(originalImage, 96), "png", a.toFile()); - ImageIO.write(Scalr.resize(originalImage, 32), "png", as.toFile()); - } - if (userService.updateUserInfo(visitor, info)) { - result = String.format("

Your info is updated.

Back to blog.

", visitor.getName()); - } - break; - case "jid-del": - // FIXME: stop using ugnich-csv in parameters -// String[] params = request.getParameter("delete").split(";", 2); -// int res = -1; -// if (params[0].equals("xmpp")) { -// res = sql.update("DELETE FROM jids WHERE user_id=? AND jid=?", visitor.getUid(), params[1]); -// } else if (params[0].equals("xmpp-unauth")) { -// res = sql.update("DELETE FROM auth WHERE user_id=? AND protocol='xmpp' AND account=?", visitor.getUid(), params[1]); -// } -// if (res == 1) { -// result = "

Deleted. Back.

"; -// } else { -// result = "

Error

"; -// } - break; - case "email": - String newHash = userService.updateSecretEmail(visitor); - if (StringUtils.isNotEmpty(newHash)) { - result = String.format("

New secret email: %s@mail.juick.com

" + - "

Back.

", newHash); - } else { - throw new HttpBadRequestException(); - } - break; - case "email-add": - try { - emailService.verifyAddressByCode(visitor.getUid(), account); - } catch (EmptyResultDataAccessException e) { - String authCode = UserUtils.generateHash(8); - if (emailService.addVerificationCode(visitor.getUid(), account, authCode)) { - Session session = Session.getDefaultInstance(System.getProperties()); - try { - MimeMessage message = new MimeMessage(session); - message.setFrom(new InternetAddress("noreply@mail.juick.com")); - message.addRecipient(Message.RecipientType.TO, new InternetAddress(account)); - message.setSubject("Juick authorization link"); - message.setText(String.format("Follow link to attach this email to Juick account:\n" + - "http://juick.com/settings?page=auth-email&code=%s\n\n" + - "If you don't know, what this mean - just ignore this mail.\n", authCode)); - Transport.send(message); - result = "

Authorization link has been sent to your email. Follow it to proceed.

" + - "

Back

"; - - } catch (MessagingException ex) { - logger.error("mail exception", ex); - throw new HttpBadRequestException(); - } - } - } - break; - case "email-del": - if (emailService.deleteEmail(visitor.getUid(), account)) { - result = "

Deleted. Back.

"; - } else { - result = "

An error occured while deleting.

"; - } - break; - case "email-subscr": - if (emailService.setSubscriptionHour(visitor.getUid(), account, time)) { - result = String.format("

Saved! Will send to %s at %s:00 GMT." + - "

Back

", account, time); - } else { - result = "

Disabled.

Back

"; - } - break; - case "twitter-del": - crosspostService.deleteTwitterToken(visitor.getUid()); - // FIXME: use spring-security -// for (Cookie cookie : request.getCookies()) { -// if (cookie.getName().equals("request_token")) { -// cookie.setMaxAge(0); -// response.addCookie(cookie); -// } -// if (cookie.getName().equals("request_token_secret")) { -// cookie.setMaxAge(0); -// response.addCookie(cookie); -// } -// } - result = "

Back

"; - break; - case "telegram-del": - telegramService.deleteTelegramUser(visitor.getUid()); - result = "

Back

"; - break; - case "facebook-disable": - crosspostService.disableFBCrosspost(visitor.getUid()); - result = "

Back

"; - break; - case "facebook-enable": - crosspostService.enableFBCrosspost(visitor.getUid()); - result = "

Back

"; - break; - case "vk-del": - crosspostService.deleteVKUser(visitor.getUid()); - result = "

Back

"; - break; - default: - throw new HttpBadRequestException(); - } - context.put("title", "Настройки"); - context.put("result", result); - return "views/settings_result"; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/ShowMessageController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/ShowMessageController.java deleted file mode 100644 index 93039a37..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/ShowMessageController.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.User; -import com.juick.server.util.HttpNotFoundException; -import com.juick.service.MessagesService; -import com.juick.service.UserService; -import com.juick.util.WebUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.math.NumberUtils; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.inject.Inject; - -/** - * Created by aalexeev on 11/21/16. - */ -@Controller -public class ShowMessageController { - @Inject - private UserService userService; - @Inject - private MessagesService messagesService; - - - @RequestMapping("/{anything}") - public String parseAnything( - @PathVariable String anything, - @RequestParam(required = false, defaultValue = "0") int before, - Model model) { - - if (before == 0) { - boolean isPostNumber = WebUtils.isPostNumber(anything); - int messageId = isPostNumber ? - NumberUtils.toInt(anything) : 0; - - if (isPostNumber && anything.equals(Integer.toString(messageId))) { - if (messageId > 0) { - com.juick.User author = messagesService.getMessageAuthor(messageId); - - if (author != null) - return "redirect:/" + author.getName() + "/" + anything; - } - - model.addAttribute("messageId", anything); - - throw new HttpNotFoundException(); - } - } - return showUserMessages(anything, null, before, model); - } - - //@RequestMapping("/{userName}/tag/{tagName}") - public String showUserMessagesByTag( - @PathVariable String userName, - @PathVariable String tagName, - @RequestParam(required = false, defaultValue = "0") int before, - Model model) { - - return showUserMessages(userName, tagName, before, model); - } - - private String showUserMessages( - String userName, - String tagName, - int before, - Model model) { - // Check validity of user name before quering from database - if (WebUtils.isNotUserName(userName)) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - User user = userService.getUserByName(userName); - if (user.getUid() == 0) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - return "views/index"; - } - - //@RequestMapping("/{userName}/friends") - public String getFriends( - @PathVariable String userName, - Model model) { - // Check validity of user name before quering from database - if (WebUtils.isNotUserName(userName)) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - User user = userService.getUserByName(userName); - if (user.getUid() == 0) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - return "views/index"; - } - - //@RequestMapping("/{userName}/readers") - public String getReaders( - @PathVariable String userName, - Model model) { - // Check validity of user name before quering from database - if (WebUtils.isNotUserName(userName)) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - User user = userService.getUserByName(userName); - if (user.getUid() == 0) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - return "views/index"; - } - - @RequestMapping("/{userName}/tags") - public String geTags( - @PathVariable String userName, - Model model) { - // Check validity of user name before quering from database - if (WebUtils.isNotUserName(userName)) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - User user = userService.getUserByName(userName); - if (user.getUid() == 0) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - return "views/index"; - } - - //@RequestMapping("/{userName}/{postNumber}") - public String checkShowPost( - @PathVariable String userName, - @PathVariable String postNumber, - Model model) { - // Check validity of post number before quering from database - if (WebUtils.isNotPostNumber(postNumber)) { - model.addAttribute("messageId", postNumber); - throw new HttpNotFoundException(); - } - - // Check validity of user name before quering from database - if (WebUtils.isNotUserName(userName)) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - User user = userService.getUserByName(userName); - if (user.getUid() == 0) { - model.addAttribute("userName", userName); - throw new HttpNotFoundException(); - } - - - return "views/thread"; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java deleted file mode 100644 index 8c4ab46d..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/TagController.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.Message; -import com.juick.User; -import com.juick.server.util.HttpNotFoundException; -import com.juick.service.AdsService; -import com.juick.service.MessagesService; -import com.juick.service.TagService; -import com.juick.service.UserService; -import com.juick.util.UserUtils; -import com.juick.www.helpers.QueryString; -import org.apache.commons.lang3.CharEncoding; -import org.apache.commons.lang3.StringEscapeUtils; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.inject.Inject; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -/** - * Created by aalexeev on 11/21/16. - */ -@Controller -public class TagController { - @Inject - private TagService tagService; - @Inject - private MessagesService messagesService; - @Inject - private AdsService adsService; - @Inject - private UserService userService; - - - @RequestMapping("/tag/{tagName}") - protected String doGet( - @PathVariable("tagName") String paramTagStr, - @RequestParam(value = "before", required = false, defaultValue = "0") Integer paramBefore, - @QueryString Optional queryString, - ModelMap model) throws UnsupportedEncodingException { - User visitor = UserUtils.getCurrentUser(); - - com.juick.Tag paramTag = tagService.getTag(paramTagStr, false); - if (paramTag == null) { - throw new HttpNotFoundException(); - } else if (paramTag.SynonymID > 0 && paramTag.TID != paramTag.SynonymID) { - com.juick.Tag synTag = tagService.getTag(paramTag.SynonymID); - String url = "/tag/" + URLEncoder.encode(synTag.getName(), CharEncoding.UTF_8); - if (queryString.isPresent()) { - url += "?" + queryString.get(); - } - return "redirect:" + url; - } else if (!paramTag.getName().equals(paramTagStr)) { - String url = "/tag/" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8); - if (queryString.isPresent()) { - url += "?" + queryString.get(); - } - return "redirect:" + url; - } - - int visitor_uid = visitor != null ? visitor.getUid() : 0; - - String title = "*" + StringEscapeUtils.escapeHtml4(paramTag.getName()); - List mids = messagesService.getTag(paramTag.TID, visitor_uid, paramBefore, (visitor == null) ? 40 : 20); - model.addAttribute("title", title); - if (tagService.getTagNoIndex(paramTag.TID)) { - model.addAttribute("headers", ""); - } else if (paramBefore > 0 || mids.size() < 5) { - model.addAttribute("headers", ""); - } - if (mids.size() > 0) { - int vuid = visitor != null ? visitor.getUid() : 0; - int ad_mid = adsService.getAdMid(vuid); - if (ad_mid > 0 && mids.indexOf(ad_mid) == -1) { - mids.add(0, ad_mid); - adsService.logAdMid(vuid, ad_mid); - } else { - ad_mid = 0; - } - } - List msgs = messagesService.getMessages(mids); - List blUIDs = userService.checkBL(visitor_uid, - msgs.stream().map(m -> m.getUser().getUid()).collect(Collectors.toList())); - model.addAttribute("msgs", - msgs.stream().map(msg -> { - msg.ReadOnly |= blUIDs.contains(msg.getUser().getUid()); - if (msg.ReadOnly) { - msg.ReadOnly = visitor.getUid() != msg.getUser().getUid(); - } - return msg; - }).collect(Collectors.toList()) - ); - if (mids.size() >= 20) { - String nextpage = "/tag/" + URLEncoder.encode(paramTag.getName(), CharEncoding.UTF_8) + "?before=" + mids.get(mids.size() - 1); - model.addAttribute("nextpage", nextpage); - } - model.addAttribute("tags", tagService.getPopularTags()); - return "views/index"; - } - - @RequestMapping("/tag") - public String redirectToMain() { - return "redirect:/"; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/controllers/ThreadController.java b/juick-spring-www/src/main/java/com/juick/www/controllers/ThreadController.java deleted file mode 100644 index f8693e13..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/controllers/ThreadController.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.juick.www.controllers; - -import com.juick.server.util.HttpForbiddenException; -import com.juick.service.MessagesService; -import com.juick.service.UserService; -import com.juick.util.UserUtils; -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.inject.Inject; - -/** - * Created by vitalyster on 20.12.2016. - */ -@Controller -public class ThreadController { - @Inject - MessagesService messagesService; - @Inject - UserService userService; - - @RequestMapping(value = "/{userName}/{mid}") - public String doGetThread( - @PathVariable int mid, - @RequestParam(required = false, value = "view") String paramView, - ModelMap modelMap) { - com.juick.User visitor = UserUtils.getCurrentUser(); - - if (!messagesService.canViewThread(mid, visitor.getUid())) { - throw new HttpForbiddenException(); - } - - com.juick.Message msg = messagesService.getMessage(mid); - - boolean listview = false; - if (paramView != null) { - if (paramView.equals("list")) { - listview = true; - if (visitor.getUid() > 0) { - userService.setUserOptionInt(visitor.getUid(), "repliesview", 1); - } - } else if (paramView.equals("tree") && visitor.getUid() > 0) { - userService.setUserOptionInt(visitor.getUid(), "repliesview", 0); - } - } else if (visitor.getUid() > 0 && userService.getUserOptionInt(visitor.getUid(), "repliesview", 0) == 1) { - listview = true; - } - - String title = msg.getUser().getName() + ": " + msg.getTagsString(); - - modelMap.put("title", title); - String headers = ""; - if (paramView != null) { - headers += ""; - } - if (msg.Hidden) { - headers += ""; - } - modelMap.put("headers", headers); - modelMap.put("msg", msg); - modelMap.put("listview", listview); - return "views/thread"; - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/formatter/SpringDateFormatter.java b/juick-spring-www/src/main/java/com/juick/www/formatter/SpringDateFormatter.java deleted file mode 100644 index bbc776c2..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/formatter/SpringDateFormatter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.juick.www.formatter; - -import com.juick.util.DateFormatter; -import org.springframework.context.MessageSource; -import org.springframework.format.Formatter; - -import javax.annotation.Resource; -import java.text.ParseException; -import java.util.Date; -import java.util.Locale; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -/** - * Created by aalexeev on 11/22/16. - */ -public class SpringDateFormatter implements Formatter { - @Resource - private MessageSource messageSource; - private ConcurrentMap formattersMap = - new ConcurrentHashMap<>(4, 0.75f, 2); // MAX 4 languages and 4/2=2 threads for write - - - @Override - public Date parse(final String text, final Locale locale) throws ParseException { - DateFormatter formatter = formattersMap.getOrDefault( - locale, createFormatter(locale)); - - return formatter.parse(text); - } - - @Override - public String print(final Date object, final Locale locale) { - DateFormatter formatter = formattersMap.getOrDefault( - locale, createFormatter(locale)); - return formatter.format(object); - } - - private DateFormatter createFormatter(final Locale locale) { - String pattern = messageSource.getMessage("date.format", null, locale); - - return new DateFormatter(pattern); - } -} diff --git a/juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java b/juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java deleted file mode 100644 index 0eb6c76f..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/helpers/QueryString.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.juick.www.helpers; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Created by vt on 22/03/16. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.PARAMETER) -public @interface QueryString { -} \ No newline at end of file diff --git a/juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java b/juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java deleted file mode 100644 index 812c4497..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/helpers/QueryStringResolver.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.juick.www.helpers; - -import org.springframework.core.MethodParameter; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -import javax.servlet.http.HttpServletRequest; -import java.lang.annotation.Annotation; -import java.util.Optional; - -public class QueryStringResolver implements HandlerMethodArgumentResolver { - @Override - public boolean supportsParameter(MethodParameter parameter) { - Annotation[] parameterAnnotations = parameter.getParameterAnnotations(); - for (Annotation parameterAnnotation : parameterAnnotations) { - if (QueryString.class.isInstance(parameterAnnotation)) { - return true; - } - } - - return false; - } - - @Override - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); - return Optional.ofNullable(request.getQueryString()); - } -} \ No newline at end of file diff --git a/juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java b/juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java deleted file mode 100644 index a444ec4d..00000000 --- a/juick-spring-www/src/main/java/com/juick/www/util/EncodeUtils.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.juick.www.util; - -/** - * Created by vitalyster on 09.12.2016. - */ -public class EncodeUtils { - public static String encodeSphinx(String str) { - return str.replaceAll("@", "\\\\@"); - } -} -- cgit v1.2.3