Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
S
springBoot
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
WitCloud
springBoot
Commits
a43f514f
Commit
a43f514f
authored
Jan 18, 2017
by
杨伊博
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
springSecurity with database is ok
parent
5db46efd
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
659 additions
and
0 deletions
+659
-0
pom.xml
springboot-security/pom.xml
+110
-0
Application.java
...ot-security/src/main/java/com/us/example/Application.java
+20
-0
DBconfig.java
...ecurity/src/main/java/com/us/example/config/DBconfig.java
+34
-0
JpaConfig.java
...curity/src/main/java/com/us/example/config/JpaConfig.java
+61
-0
WebMvcConfig.java
...ity/src/main/java/com/us/example/config/WebMvcConfig.java
+17
-0
WebSecurityConfig.java
...rc/main/java/com/us/example/config/WebSecurityConfig.java
+42
-0
HomeController.java
...c/main/java/com/us/example/controller/HomeController.java
+21
-0
SysRoleRepositiory.java
.../src/main/java/com/us/example/dao/SysRoleRepositiory.java
+12
-0
SysUserRepository.java
...y/src/main/java/com/us/example/dao/SysUserRepository.java
+13
-0
Msg.java
...oot-security/src/main/java/com/us/example/domain/Msg.java
+37
-0
SysRole.java
...security/src/main/java/com/us/example/domain/SysRole.java
+33
-0
SysUser.java
...security/src/main/java/com/us/example/domain/SysUser.java
+98
-0
CustomUserService.java
.../main/java/com/us/example/security/CustomUserService.java
+33
-0
application.properties
...ngboot-security/src/main/resources/application.properties
+11
-0
bootstrap.min.css
...-security/src/main/resources/static/css/bootstrap.min.css
+5
-0
home.html
springboot-security/src/main/resources/templates/home.html
+58
-0
login.html
springboot-security/src/main/resources/templates/login.html
+54
-0
No files found.
springboot-security/pom.xml
0 → 100644
View file @
a43f514f
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns=
"http://maven.apache.org/POM/4.0.0"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
>
<modelVersion>
4.0.0
</modelVersion>
<groupId>
com.us
</groupId>
<artifactId>
springboot-security
</artifactId>
<version>
1.0-SNAPSHOT
</version>
<parent>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-parent
</artifactId>
<version>
1.3.0.RELEASE
</version>
</parent>
<properties>
<start-class>
com.us.Application
</start-class>
<maven.compiler.target>
1.8
</maven.compiler.target>
<maven.compiler.source>
1.8
</maven.compiler.source>
</properties>
<dependencies>
<!--springboot-->
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-data-jpa
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-thymeleaf
</artifactId>
</dependency>
<dependency>
<groupId>
org.thymeleaf.extras
</groupId>
<artifactId>
thymeleaf-extras-springsecurity4
</artifactId>
</dependency>
<!--db-->
<dependency>
<groupId>
mysql
</groupId>
<artifactId>
mysql-connector-java
</artifactId>
<version>
6.0.5
</version>
</dependency>
<dependency>
<groupId>
com.mchange
</groupId>
<artifactId>
c3p0
</artifactId>
<version>
0.9.5.2
</version>
<exclusions>
<exclusion>
<groupId>
commons-logging
</groupId>
<artifactId>
commons-logging
</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-maven-plugin
</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>
spring-snapshots
</id>
<name>
Spring Snapshots
</name>
<url>
https://repo.spring.io/snapshot
</url>
<snapshots>
<enabled>
true
</enabled>
</snapshots>
</repository>
<repository>
<id>
spring-milestones
</id>
<name>
Spring Milestones
</name>
<url>
https://repo.spring.io/milestone
</url>
<snapshots>
<enabled>
false
</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>
spring-snapshots
</id>
<name>
Spring Snapshots
</name>
<url>
https://repo.spring.io/snapshot
</url>
<snapshots>
<enabled>
true
</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>
spring-milestones
</id>
<name>
Spring Milestones
</name>
<url>
https://repo.spring.io/milestone
</url>
<snapshots>
<enabled>
false
</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
\ No newline at end of file
springboot-security/src/main/java/com/us/example/Application.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.ComponentScan
;
import
static
org
.
springframework
.
boot
.
SpringApplication
.
run
;
/**
* Created by yangyibo on 17/1/17.
*/
@ComponentScan
(
basePackages
=
"com.us.example"
)
@SpringBootApplication
public
class
Application
{
public
static
void
main
(
String
[]
args
)
{
ConfigurableApplicationContext
run
=
run
(
Application
.
class
,
args
);
}
}
springboot-security/src/main/java/com/us/example/config/DBconfig.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
config
;
import
java.beans.PropertyVetoException
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.core.env.Environment
;
import
com.mchange.v2.c3p0.ComboPooledDataSource
;
/**
* Created by yangyibo on 17/1/18.
*/
@Configuration
public
class
DBconfig
{
@Autowired
private
Environment
env
;
@Bean
(
name
=
"dataSource"
)
public
ComboPooledDataSource
dataSource
()
throws
PropertyVetoException
{
ComboPooledDataSource
dataSource
=
new
ComboPooledDataSource
();
dataSource
.
setDriverClass
(
env
.
getProperty
(
"ms.db.driverClassName"
));
dataSource
.
setJdbcUrl
(
env
.
getProperty
(
"ms.db.url"
));
dataSource
.
setUser
(
env
.
getProperty
(
"ms.db.username"
));
dataSource
.
setPassword
(
env
.
getProperty
(
"ms.db.password"
));
dataSource
.
setMaxPoolSize
(
20
);
dataSource
.
setMinPoolSize
(
5
);
dataSource
.
setInitialPoolSize
(
10
);
dataSource
.
setMaxIdleTime
(
300
);
dataSource
.
setAcquireIncrement
(
5
);
dataSource
.
setIdleConnectionTestPeriod
(
60
);
return
dataSource
;
}
}
springboot-security/src/main/java/com/us/example/config/JpaConfig.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
config
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.ComponentScan
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.data.jpa.repository.config.EnableJpaRepositories
;
import
org.springframework.orm.jpa.JpaTransactionManager
;
import
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
;
import
org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
;
import
org.springframework.transaction.PlatformTransactionManager
;
import
org.springframework.transaction.annotation.EnableTransactionManagement
;
import
javax.persistence.EntityManagerFactory
;
import
javax.sql.DataSource
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* Created by yangyibo on 17/1/18.
*/
@Configuration
@EnableJpaRepositories
(
"com.us.example.dao"
)
@EnableTransactionManagement
@ComponentScan
public
class
JpaConfig
{
@Autowired
private
DataSource
dataSource
;
@Bean
public
EntityManagerFactory
entityManagerFactory
()
{
HibernateJpaVendorAdapter
vendorAdapter
=
new
HibernateJpaVendorAdapter
();
//vendorAdapter.setShowSql(true);
//vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean
factory
=
new
LocalContainerEntityManagerFactoryBean
();
factory
.
setJpaVendorAdapter
(
vendorAdapter
);
factory
.
setPackagesToScan
(
"com.us.example.domain"
);
factory
.
setDataSource
(
dataSource
);
Map
<
String
,
Object
>
jpaProperties
=
new
HashMap
<>();
jpaProperties
.
put
(
"hibernate.ejb.naming_strategy"
,
"org.hibernate.cfg.ImprovedNamingStrategy"
);
jpaProperties
.
put
(
"hibernate.jdbc.batch_size"
,
50
);
//jpaProperties.put("hibernate.show_sql",true);
factory
.
setJpaPropertyMap
(
jpaProperties
);
factory
.
afterPropertiesSet
();
return
factory
.
getObject
();
}
@Bean
public
PlatformTransactionManager
transactionManager
()
{
JpaTransactionManager
txManager
=
new
JpaTransactionManager
();
txManager
.
setEntityManagerFactory
(
entityManagerFactory
());
return
txManager
;
}
}
springboot-security/src/main/java/com/us/example/config/WebMvcConfig.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
config
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.web.servlet.config.annotation.ViewControllerRegistry
;
import
org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
;
/**
* Created by yangyibo on 17/1/18.
*/
@Configuration
public
class
WebMvcConfig
extends
WebMvcConfigurerAdapter
{
@Override
public
void
addViewControllers
(
ViewControllerRegistry
registry
)
{
registry
.
addViewController
(
"/login"
).
setViewName
(
"login"
);
}
}
springboot-security/src/main/java/com/us/example/config/WebSecurityConfig.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
config
;
import
com.us.example.security.CustomUserService
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
import
org.springframework.security.core.userdetails.UserDetailsService
;
/**
* Created by yangyibo on 17/1/18.
*/
@Configuration
public
class
WebSecurityConfig
extends
WebSecurityConfigurerAdapter
{
@Bean
UserDetailsService
customUserService
(){
//2
return
new
CustomUserService
();
}
@Override
protected
void
configure
(
AuthenticationManagerBuilder
auth
)
throws
Exception
{
auth
.
userDetailsService
(
customUserService
());
//3
}
@Override
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
http
.
authorizeRequests
()
.
anyRequest
().
authenticated
()
//4
.
and
()
.
formLogin
()
.
loginPage
(
"/login"
)
.
failureUrl
(
"/login?error"
)
.
permitAll
()
//5
.
and
()
.
logout
().
permitAll
();
//6
}
}
springboot-security/src/main/java/com/us/example/controller/HomeController.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
controller
;
import
com.us.example.domain.Msg
;
import
org.springframework.stereotype.Controller
;
import
org.springframework.ui.Model
;
import
org.springframework.web.bind.annotation.RequestMapping
;
/**
* Created by yangyibo on 17/1/18.
*/
@Controller
public
class
HomeController
{
@RequestMapping
(
"/"
)
public
String
index
(
Model
model
){
Msg
msg
=
new
Msg
(
"测试标题"
,
"测试内容"
,
"额外信息,只对管理员显示"
);
model
.
addAttribute
(
"msg"
,
msg
);
return
"home"
;
}
}
springboot-security/src/main/java/com/us/example/dao/SysRoleRepositiory.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
dao
;
import
com.us.example.domain.SysRole
;
import
org.springframework.data.jpa.repository.JpaRepository
;
/**
* Created by yangyibo on 17/1/18.
*/
public
interface
SysRoleRepositiory
extends
JpaRepository
<
SysRole
,
Integer
>
{
SysRole
findById
(
Integer
id
);
}
springboot-security/src/main/java/com/us/example/dao/SysUserRepository.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
dao
;
import
com.us.example.domain.SysUser
;
import
org.springframework.data.jpa.repository.JpaRepository
;
/**
* Created by yangyibo on 17/1/18.
*/
public
interface
SysUserRepository
extends
JpaRepository
<
SysUser
,
Long
>
{
SysUser
findByUsername
(
String
username
);
}
springboot-security/src/main/java/com/us/example/domain/Msg.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
domain
;
/**
* Created by yangyibo on 17/1/17.
*/
public
class
Msg
{
private
String
title
;
private
String
content
;
private
String
etraInfo
;
public
Msg
(
String
title
,
String
content
,
String
etraInfo
)
{
super
();
this
.
title
=
title
;
this
.
content
=
content
;
this
.
etraInfo
=
etraInfo
;
}
public
String
getTitle
()
{
return
title
;
}
public
void
setTitle
(
String
title
)
{
this
.
title
=
title
;
}
public
String
getContent
()
{
return
content
;
}
public
void
setContent
(
String
content
)
{
this
.
content
=
content
;
}
public
String
getEtraInfo
()
{
return
etraInfo
;
}
public
void
setEtraInfo
(
String
etraInfo
)
{
this
.
etraInfo
=
etraInfo
;
}
}
springboot-security/src/main/java/com/us/example/domain/SysRole.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
domain
;
import
javax.persistence.Entity
;
import
javax.persistence.GeneratedValue
;
import
javax.persistence.Id
;
import
javax.persistence.Table
;
/**
* Created by yangyibo on 17/1/17.
*/
@Entity
@Table
(
name
=
"Sys_Role"
)
public
class
SysRole
{
@Id
@GeneratedValue
private
Integer
id
;
private
String
name
;
public
Integer
getId
()
{
return
id
;
}
public
void
setId
(
Integer
id
)
{
this
.
id
=
id
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
}
springboot-security/src/main/java/com/us/example/domain/SysUser.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
domain
;
import
java.util.*
;
import
javax.persistence.*
;
import
org.springframework.security.core.GrantedAuthority
;
import
org.springframework.security.core.authority.SimpleGrantedAuthority
;
import
org.springframework.security.core.userdetails.UserDetails
;
/**
* Created by yangyibo on 17/1/17.
*/
@Entity
@Table
(
name
=
"Sys_User"
)
public
class
SysUser
implements
UserDetails
{
//用户实体实现UserDetails接口,我门的用户实体即位 security 所使用的用户
private
static
final
long
serialVersionUID
=
1L
;
@Id
@GeneratedValue
private
Long
id
;
private
String
username
;
private
String
password
;
private
Integer
role_id
;
@Transient
//此字段不映射到数据库
private
String
authority
;
@Override
public
Collection
<?
extends
GrantedAuthority
>
getAuthorities
()
{
//重写getAuthorities方法,将用户角色作为权限
List
<
GrantedAuthority
>
auths
=
new
ArrayList
<>();
auths
.
add
(
new
SimpleGrantedAuthority
(
this
.
authority
));
return
auths
;
}
@Override
public
boolean
isAccountNonExpired
()
{
return
true
;
}
@Override
public
boolean
isAccountNonLocked
()
{
return
true
;
}
@Override
public
boolean
isCredentialsNonExpired
()
{
return
true
;
}
@Override
public
boolean
isEnabled
()
{
return
true
;
}
public
Long
getId
()
{
return
id
;
}
public
void
setId
(
Long
id
)
{
this
.
id
=
id
;
}
public
String
getUsername
()
{
return
username
;
}
public
void
setUsername
(
String
username
)
{
this
.
username
=
username
;
}
public
String
getPassword
()
{
return
password
;
}
public
void
setPassword
(
String
password
)
{
this
.
password
=
password
;
}
public
Integer
getRole_id
()
{
return
role_id
;
}
public
void
setRole_id
(
Integer
role_id
)
{
this
.
role_id
=
role_id
;
}
public
String
getAuthority
()
{
return
authority
;
}
public
void
setAuthority
(
String
authority
)
{
this
.
authority
=
authority
;
}
}
springboot-security/src/main/java/com/us/example/security/CustomUserService.java
0 → 100644
View file @
a43f514f
package
com
.
us
.
example
.
security
;
import
com.us.example.dao.SysRoleRepositiory
;
import
com.us.example.dao.SysUserRepository
;
import
com.us.example.domain.SysUser
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.security.core.userdetails.UserDetails
;
import
org.springframework.security.core.userdetails.UserDetailsService
;
import
org.springframework.security.core.userdetails.UsernameNotFoundException
;
import
org.springframework.stereotype.Service
;
/**
* Created by yangyibo on 17/1/18.
*/
@Service
public
class
CustomUserService
implements
UserDetailsService
{
//1
@Autowired
SysUserRepository
userRepository
;
@Autowired
SysRoleRepositiory
sysRoleRepositiory
;
@Override
public
UserDetails
loadUserByUsername
(
String
username
)
{
//2
SysUser
user
=
userRepository
.
findByUsername
(
username
);
user
.
setAuthority
(
sysRoleRepositiory
.
findById
(
user
.
getRole_id
()).
getName
());
if
(
user
==
null
){
throw
new
UsernameNotFoundException
(
"用户名不存在"
);
}
return
user
;
//3
}
}
springboot-security/src/main/resources/application.properties
0 → 100755
View file @
a43f514f
ms.db.driverClassName
=
com.mysql.jdbc.Driver
ms.db.url
=
jdbc:mysql://localhost:3306/cache?characterEncoding=utf-8&useSSL=false
ms.db.username
=
root
ms.db.password
=
admin
ms.db.maxActive
=
500
logging.level.org.springframework.security
=
INFO
spring.thymeleaf.cache
=
false
spring.jpa.hibernate.ddl-auto
=
update
spring.jpa.show-sql
=
true
\ No newline at end of file
springboot-security/src/main/resources/static/css/bootstrap.min.css
0 → 100755
View file @
a43f514f
This source diff could not be displayed because it is too large. You can
view the blob
instead.
springboot-security/src/main/resources/templates/home.html
0 → 100755
View file @
a43f514f
<!DOCTYPE html>
<html
xmlns:th=
"http://www.thymeleaf.org"
xmlns:sec=
"http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
>
<!-- 1 -->
<head>
<meta
content=
"text/html;charset=UTF-8"
/>
<title
sec:authentication=
"name"
></title>
<!-- 2 -->
<link
rel=
"stylesheet"
th:href=
"@{css/bootstrap.min.css}"
/>
<style
type=
"text/css"
>
body
{
padding-top
:
50px
;
}
.starter-template
{
padding
:
40px
15px
;
text-align
:
center
;
}
</style>
</head>
<body>
<nav
class=
"navbar navbar-inverse navbar-fixed-top"
>
<div
class=
"container"
>
<div
class=
"navbar-header"
>
<a
class=
"navbar-brand"
href=
"#"
>
Spring Security演示
</a>
</div>
<div
id=
"navbar"
class=
"collapse navbar-collapse"
>
<ul
class=
"nav navbar-nav"
>
<li><a
th:href=
"@{/}"
>
首页
</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</nav>
<div
class=
"container"
>
<div
class=
"starter-template"
>
<h1
th:text=
"${msg.title}"
></h1>
<p
class=
"bg-primary"
th:text=
"${msg.content}"
></p>
<div
sec:authorize=
"hasRole('ROLE_ADMIN')"
>
<!-- 3 -->
<p
class=
"bg-info"
th:text=
"${msg.etraInfo}"
></p>
</div>
<div
sec:authorize=
"hasRole('ROLE_USER')"
>
<!-- 4-->
<p
class=
"bg-info"
>
无更多信息显示
</p>
</div>
<form
th:action=
"@{/logout}"
method=
"post"
>
<input
type=
"submit"
class=
"btn btn-primary"
value=
"注销"
/>
<!-- 5 -->
</form>
</div>
</div>
</body>
</html>
springboot-security/src/main/resources/templates/login.html
0 → 100755
View file @
a43f514f
<!DOCTYPE html>
<html
xmlns:th=
"http://www.thymeleaf.org"
>
<head>
<meta
content=
"text/html;charset=UTF-8"
/>
<title>
登录页面
</title>
<link
rel=
"stylesheet"
th:href=
"@{css/bootstrap.min.css}"
/>
<style
type=
"text/css"
>
body
{
padding-top
:
50px
;
}
.starter-template
{
padding
:
40px
15px
;
text-align
:
center
;
}
</style>
</head>
<body>
<nav
class=
"navbar navbar-inverse navbar-fixed-top"
>
<div
class=
"container"
>
<div
class=
"navbar-header"
>
<a
class=
"navbar-brand"
href=
"#"
>
Spring Security演示
</a>
</div>
<div
id=
"navbar"
class=
"collapse navbar-collapse"
>
<ul
class=
"nav navbar-nav"
>
<li><a
th:href=
"@{/}"
>
首页
</a></li>
</ul>
</div>
<!--/.nav-collapse -->
</div>
</nav>
<div
class=
"container"
>
<div
class=
"starter-template"
>
<p
th:if=
"${param.logout}"
class=
"bg-warning"
>
已成功注销
</p>
<!-- 1 -->
<p
th:if=
"${param.error}"
class=
"bg-danger"
>
有错误,请重试
</p>
<!-- 2 -->
<h2>
使用账号密码登录
</h2>
<form
name=
"form"
th:action=
"@{/login}"
action=
"/login"
method=
"POST"
>
<!-- 3 -->
<div
class=
"form-group"
>
<label
for=
"username"
>
账号
</label>
<input
type=
"text"
class=
"form-control"
name=
"username"
value=
""
placeholder=
"账号"
/>
</div>
<div
class=
"form-group"
>
<label
for=
"password"
>
密码
</label>
<input
type=
"password"
class=
"form-control"
name=
"password"
placeholder=
"密码"
/>
</div>
<input
type=
"submit"
id=
"login"
value=
"Login"
class=
"btn btn-primary"
/>
</form>
</div>
</div>
</body>
</html>
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment