Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Σταύρος Παπαδάκης
gredu_labs
Commits
16e3778b
Commit
16e3778b
authored
Feb 11, 2016
by
Vassilis Kanellopoulos
Browse files
link user with school
parent
92c499df
Changes
14
Hide whitespace changes
Inline
Side-by-side
config/app.config.php
View file @
16e3778b
...
...
@@ -10,6 +10,7 @@
return
[
'modules'
=>
[
'module/application/bootstrap.php'
,
'module/assets_manager/bootstrap.php'
,
'module/authentication/bootstrap.php'
,
'module/authorization/bootstrap.php'
,
...
...
@@ -19,7 +20,6 @@ return [
'module/sch_inventory/bootstrap.php'
,
'module/sch_sync/bootstrap.php'
,
'module/schools/bootstrap.php'
,
'module/application/bootstrap.php'
,
],
'cache_config'
=>
'data/cache/config/settings.php'
,
];
module/application/bootstrap.php
View file @
16e3778b
...
...
@@ -12,6 +12,14 @@ return function (Slim\App $app) {
$container
=
$app
->
getContainer
();
// setup RedbeanPHP
define
(
'REDBEAN_MODEL_PREFIX'
,
''
);
RedBeanPHP\R
::
setup
(
$container
[
'settings'
][
'db'
][
'dsn'
],
$container
[
'settings'
][
'db'
][
'user'
],
$container
[
'settings'
][
'db'
][
'pass'
]
);
$container
[
'autoloader'
]
->
addPsr4
(
'GrEduLabs\\Application\\'
,
__DIR__
.
'/src'
);
$container
[
'view'
]
=
function
(
$c
)
{
...
...
@@ -68,29 +76,19 @@ return function (Slim\App $app) {
};
$events
=
$container
[
'events'
];
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$container
)
{
session_name
(
'GrEduLabs'
);
session_start
();
// setup RedbeanPHP
RedBeanPHP\R
::
setup
(
$container
[
'settings'
][
'db'
][
'dsn'
],
$container
[
'settings'
][
'db'
][
'user'
],
$container
[
'settings'
][
'db'
][
'pass'
]
);
define
(
'REDBEAN_MODEL_PREFIX'
,
''
);
},
10000000
);
},
100000000000
);
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$container
)
{
try
{
$container
[
'router'
]
->
getNamedRoute
(
'user.login'
)
->
add
(
'csrf'
);
}
catch
(
\
RuntimeException
$e
)
{
// eat it
foreach
(
$container
[
'router'
]
->
getRoutes
()
as
$route
)
{
if
(
'user.login'
===
$route
->
getName
())
{
$route
->
add
(
'csrf'
);
break
;
}
}
});
...
...
module/authentication/bootstrap.php
View file @
16e3778b
...
...
@@ -11,7 +11,6 @@
return
function
(
Slim
\
App
$app
)
{
$container
=
$app
->
getContainer
();
$events
=
$container
[
'events'
];
$container
[
'autoloader'
]
->
addPsr4
(
'GrEduLabs\\Authentication\\'
,
__DIR__
.
'/src'
);
...
...
@@ -22,7 +21,7 @@ return function (Slim\App $app) {
$container
[
'authentication_adapter'
]
=
function
(
$c
)
{
return
new
GrEduLabs\Authentication\Adapter\RedBeanPHP
(
$c
[
'events'
],
$c
[
'
authentication_
identity_class'
],
$c
[
'identity_class
_resolver
'
],
$c
[
'authentication_crypt'
]
);
};
...
...
@@ -34,9 +33,9 @@ return function (Slim\App $app) {
);
};
$container
[
'
authentication_identity_class'
]
=
function
(
$c
)
{
return
GrEduLabs\Authentication\Identity
::
class
;
};
$container
[
'
identity_class_resolver'
]
=
$container
->
protect
(
function
()
{
return
'
GrEduLabs\
\
Authentication\
\
Identity
'
;
}
)
;
$container
[
'authentication_crypt'
]
=
function
(
$c
)
{
$service
=
new
Zend\Crypt\Password\Bcrypt
();
...
...
@@ -50,27 +49,6 @@ return function (Slim\App $app) {
return
$service
;
};
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$container
)
{
$container
->
extend
(
'view'
,
function
(
$view
,
$c
)
{
$view
->
getEnvironment
()
->
getLoader
()
->
prependPath
(
__DIR__
.
'/templates'
);
$view
->
addExtension
(
new
GrEduLabs\Authentication\Twig\Extension\Identity
(
$c
[
'authentication_service'
]
));
return
$view
;
});
});
$events
(
'on'
,
'authenticate.success'
,
function
(
$stop
,
$identity
)
use
(
$container
)
{
if
(
isset
(
$container
[
'logger'
]))
{
$container
[
'logger'
]
->
info
(
sprintf
(
'Authentication through %s for %s'
,
$identity
->
authenticationSource
,
$identity
->
mail
));
}
});
$container
[
GrEduLabs\Authentication\Action\User\Login
::
class
]
=
function
(
$c
)
{
return
new
GrEduLabs\Authentication\Action\User\Login
(
...
...
@@ -90,14 +68,6 @@ return function (Slim\App $app) {
);
};
$app
->
group
(
'/user'
,
function
()
{
$this
->
map
([
'GET'
,
'POST'
],
'/login'
,
GrEduLabs\Authentication\Action\User\Login
::
class
)
->
setName
(
'user.login'
);
$this
->
get
(
'/logout'
,
GrEduLabs\Authentication\Action\User\Logout
::
class
)
->
setName
(
'user.logout'
);
});
$nav
=
$container
[
'settings'
]
->
get
(
'navigation'
);
$nav
[
'authentication'
]
=
[
'login'
=>
[
...
...
@@ -113,4 +83,41 @@ return function (Slim\App $app) {
],
];
$container
[
'settings'
]
->
set
(
'navigation'
,
$nav
);
$events
=
$container
[
'events'
];
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$app
,
$container
)
{
$container
->
extend
(
'view'
,
function
(
$view
,
$c
)
{
$view
->
getEnvironment
()
->
getLoader
()
->
prependPath
(
__DIR__
.
'/templates'
);
$view
->
addExtension
(
new
GrEduLabs\Authentication\Twig\Extension\Identity
(
$c
[
'authentication_service'
]
));
return
$view
;
});
$app
->
group
(
'/user'
,
function
()
{
$this
->
map
([
'GET'
,
'POST'
],
'/login'
,
GrEduLabs\Authentication\Action\User\Login
::
class
)
->
setName
(
'user.login'
);
$this
->
get
(
'/logout'
,
GrEduLabs\Authentication\Action\User\Logout
::
class
)
->
setName
(
'user.logout'
);
});
$app
->
add
(
function
(
$req
,
$res
,
$next
)
use
(
$container
)
{
$req
=
$req
->
withAttribute
(
'identity'
,
$container
[
'authentication_service'
]
->
getIdentity
());
return
$next
(
$req
,
$res
);
});
});
$events
(
'on'
,
'authenticate.success'
,
function
(
$stop
,
$identity
)
use
(
$container
)
{
if
(
isset
(
$container
[
'logger'
]))
{
$container
[
'logger'
]
->
info
(
sprintf
(
'Authentication through %s for %s'
,
$identity
->
authenticationSource
,
$identity
->
mail
));
}
});
};
module/authentication/src/Adapter/RedBeanPHP.php
View file @
16e3778b
...
...
@@ -28,20 +28,20 @@ class RedBeanPHP extends AbstractAdapter
protected
$events
;
/**
* @var
string
* @var
callable
*/
protected
$
i
dentityClass
;
protected
$
resolveI
dentityClass
;
/**
* @var PasswordInterface
*/
protected
$crypt
;
public
function
__construct
(
callable
$events
,
$i
dentityClass
,
PasswordInterface
$crypt
)
public
function
__construct
(
callable
$events
,
callable
$resolveI
dentityClass
,
PasswordInterface
$crypt
)
{
$this
->
events
=
$events
;
$this
->
i
dentityClass
=
(
string
)
$i
dentityClass
;
$this
->
crypt
=
$crypt
;
$this
->
events
=
$events
;
$this
->
resolveI
dentityClass
=
$resolveI
dentityClass
;
$this
->
crypt
=
$crypt
;
}
public
function
authenticate
()
...
...
@@ -69,8 +69,9 @@ class RedBeanPHP extends AbstractAdapter
return
new
Result
(
Result
::
FAILURE_CREDENTIAL_INVALID
,
null
,
[
self
::
$failMessage
]);
}
$identityClass
=
$this
->
i
dentityClass
;
$identityClass
=
call_user_func
(
$this
->
resolveI
dentityClass
)
;
$identity
=
new
$identityClass
(
$user
->
id
,
$user
->
uid
,
$user
->
mail
,
$user
->
displayName
,
...
...
module/authentication/src/Identity.php
View file @
16e3778b
...
...
@@ -14,6 +14,8 @@ use JsonSerializable;
class
Identity
implements
JsonSerializable
{
protected
$id
;
protected
$uid
;
protected
$mail
;
...
...
@@ -24,8 +26,9 @@ class Identity implements JsonSerializable
protected
$authenticationSource
;
public
function
__construct
(
$uid
,
$mail
,
$displayName
,
$officeName
,
$authenticationSource
)
public
function
__construct
(
$id
,
$uid
,
$mail
,
$displayName
,
$officeName
,
$authenticationSource
)
{
$this
->
id
=
$id
;
$this
->
uid
=
$uid
;
$this
->
mail
=
$mail
;
$this
->
displayName
=
$displayName
;
...
...
@@ -47,14 +50,15 @@ class Identity implements JsonSerializable
return
$this
->
displayName
;
}
public
function
get
Ui
d
()
public
function
get
I
d
()
{
return
$this
->
u
id
;
return
$this
->
id
;
}
public
function
toArray
()
{
return
[
'id'
=>
$this
->
id
,
'uid'
=>
$this
->
uid
,
'mail'
=>
$this
->
mail
,
'displayName'
=>
$this
->
displayName
,
...
...
module/authorization/bootstrap.php
View file @
16e3778b
...
...
@@ -44,6 +44,13 @@ return function (Slim\App $app) {
return
new
GrEduLabs\Authorization\RouteGuard
(
$c
[
GrEduLabs\Authorization\Acl
::
class
],
$role
);
};
$container
[
GrEduLabs\Authorization\Middleware\RoleProvider
::
class
]
=
function
(
$c
)
{
return
new
GrEduLabs\Authorization\Middleware\RoleProvider
(
$c
[
'authentication_service'
],
$c
[
GrEduLabs\Authorization\Acl
::
class
]
);
};
$container
[
GrEduLabs\Authorization\Listener\RoleProvider
::
class
]
=
function
(
$c
)
{
return
new
GrEduLabs\Authorization\Listener\RoleProvider
(
$c
[
'authentication_storage'
],
...
...
@@ -53,15 +60,12 @@ return function (Slim\App $app) {
$events
=
$container
[
'events'
];
$events
(
'on'
,
'authenticate.success'
,
function
(
$stop
,
$identity
)
use
(
$container
)
{
$listener
=
$container
[
GrEduLabs\Authorization\Listener\RoleProvider
::
class
];
$listener
(
$stop
,
$identity
);
});
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$app
,
$container
)
{
$container
->
extend
(
'authentication_identity_class'
,
function
(
$c
)
{
return
GrEduLabs\Authorization\Identity
::
class
;
$container
->
extend
(
'identity_class_resolver'
,
function
()
{
return
function
()
{
return
'GrEduLabs\\Authorization\\Identity'
;
};
});
$container
->
extend
(
GrEduLabs\Application\Twig\Extension\Navigation
::
class
,
function
(
$navigation
,
$c
)
{
...
...
@@ -70,6 +74,13 @@ return function (Slim\App $app) {
->
setCurrentRole
(
call_user_func
(
$c
[
'current_role'
]));
});
foreach
(
$container
[
'router'
]
->
getRoutes
()
as
$route
)
{
if
(
'user.login'
===
$route
->
getName
())
{
$route
->
add
(
GrEduLabs\Authorization\Middleware\RoleProvider
::
class
);
break
;
}
}
$app
->
add
(
GrEduLabs\Authorization\RouteGuard
::
class
);
});
...
...
module/authorization/src/
Listener
/RoleProvider.php
→
module/authorization/src/
Middleware
/RoleProvider.php
View file @
16e3778b
...
...
@@ -8,32 +8,42 @@
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace
GrEduLabs\Authorization\
Listener
;
namespace
GrEduLabs\Authorization\
Middleware
;
use
GrEduLabs\Authorization\RoleAwareInterface
;
use
Psr\Http\Message\ResponseInterface
as
Response
;
use
Psr\Http\Message\ServerRequestInterface
as
Request
;
use
RedBeanPHP\R
;
use
Zend\Authentication\
Storage\StorageInterfa
ce
;
use
Zend\Authentication\
AuthenticationServi
ce
;
use
Zend\Permissions\Acl\AclInterface
;
class
RoleProvider
{
private
$
session
;
private
$
authService
;
private
$acl
;
public
function
__construct
(
StorageInterface
$session
,
AclInterface
$acl
)
public
function
__construct
(
AuthenticationService
$authService
,
AclInterface
$acl
)
{
$this
->
session
=
$session
;
$this
->
acl
=
$acl
;
$this
->
authService
=
$authService
;
$this
->
acl
=
$acl
;
}
public
function
__invoke
(
callable
$stop
,
RoleAwareInterface
$identity
)
public
function
__invoke
(
Request
$req
,
Response
$res
,
callable
$next
)
{
$user
=
R
::
findOne
(
'user'
,
'mail = ?'
,
[
$identity
->
mail
]);
$role
=
(
$user
&&
isset
(
$user
->
role
))
?
$user
->
role
:
'user'
;
$validRoles
=
$this
->
acl
->
getRoles
();
$role
=
(
in_array
(
$role
,
$validRoles
))
?
$role
:
'user'
;
$identity
->
setRole
(
$role
);
$this
->
session
->
write
(
$identity
);
$res
=
$next
(
$req
,
$res
);
$identity
=
$this
->
authService
->
getIdentity
();
if
(
$identity
&&
$identity
instanceof
RoleAwareInterface
)
{
$user
=
R
::
load
(
'user'
,
$identity
->
id
);
$role
=
(
$user
&&
isset
(
$user
->
role
))
?
$user
->
role
:
'user'
;
$validRoles
=
$this
->
acl
->
getRoles
();
$role
=
(
in_array
(
$role
,
$validRoles
))
?
$role
:
'user'
;
$identity
->
setRole
(
$role
);
$this
->
authService
->
getStorage
()
->
write
(
$identity
);
}
return
$res
;
}
}
module/sch_sso/bootstrap.php
View file @
16e3778b
...
...
@@ -68,7 +68,7 @@ return function (Slim\App $app) {
$c
[
'init_cas'
],
$c
[
'is_allowed'
],
$c
[
'events'
],
$c
[
'
authentication_
identity_class'
],
$c
[
'identity_class
_resolver
'
],
$c
[
'router'
]
->
pathFor
(
'user.logout.sso'
)
);
};
...
...
@@ -114,6 +114,11 @@ return function (Slim\App $app) {
}
});
$app
->
get
(
'/user/login/sso'
,
SchSSO\Action\Login
::
class
)
->
setName
(
'user.login.sso'
);
$app
->
get
(
'/user/logout/sso'
,
SchSSO\Action\Logout
::
class
)
->
setName
(
'user.logout.sso'
);
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$app
,
$container
)
{
$app
->
get
(
'/user/login/sso'
,
SchSSO\Action\Login
::
class
)
->
add
(
GrEduLabs\Authorization\Middleware\RoleProvider
::
class
)
->
setName
(
'user.login.sso'
);
$app
->
get
(
'/user/logout/sso'
,
SchSSO\Action\Logout
::
class
)
->
setName
(
'user.logout.sso'
);
},
10
);
};
module/sch_sso/src/Adapter/Cas.php
View file @
16e3778b
...
...
@@ -34,7 +34,7 @@ class Cas implements AdapterInterface
/**
* @var string
*/
protected
$
i
dentityClass
;
protected
$
resolveI
dentityClass
;
/**
* @var string
...
...
@@ -46,14 +46,14 @@ class Cas implements AdapterInterface
callable
$initCas
,
callable
$isAllowed
,
callable
$events
,
$i
dentityClass
,
callable
$resolveI
dentityClass
,
$ssoLogoutUrl
)
{
$this
->
initCas
=
$initCas
;
$this
->
isAllowed
=
$isAllowed
;
$this
->
events
=
$events
;
$this
->
i
dentityClass
=
(
string
)
$i
dentityClass
;
$this
->
ssoLogoutUrl
=
(
string
)
$ssoLogoutUrl
;
$this
->
initCas
=
$initCas
;
$this
->
isAllowed
=
$isAllowed
;
$this
->
events
=
$events
;
$this
->
resolveI
dentityClass
=
$resolveI
dentityClass
;
$this
->
ssoLogoutUrl
=
(
string
)
$ssoLogoutUrl
;
}
public
function
authenticate
()
...
...
@@ -90,8 +90,9 @@ class Cas implements AdapterInterface
return
$attributes
[
$attribute
];
};
$identityClass
=
$this
->
i
dentityClass
;
$identityClass
=
call_user_func
(
$this
->
resolveI
dentityClass
)
;
$identity
=
new
$identityClass
(
null
,
$identity
,
$filterAttribute
(
'mail'
),
$filterAttribute
(
'cn'
),
...
...
module/sch_sync/bootstrap.php
View file @
16e3778b
...
...
@@ -14,33 +14,36 @@ return function (Slim\App $app) {
$container
[
'autoloader'
]
->
addPsr4
(
'SchSync\\'
,
__DIR__
.
'/src'
);
$container
[
SchSync\Middleware\CreateUser
::
class
]
=
function
(
$c
)
{
return
new
SchSync\Middleware\CreateUser
(
$c
[
'authentication_service'
],
$c
[
'router'
]
->
pathFor
(
'user.login'
),
$c
[
'router'
]
->
pathFor
(
'user.logout.sso'
),
$c
[
'flash'
],
$c
[
'logger'
]
);
};
$container
[
SchSync\Middleware\CreateSchool
::
class
]
=
function
(
$c
)
{
return
new
SchSync\Middleware\CreateSchool
(
$c
[
'ldap'
],
$c
[
SchMM\FetchUnit
::
class
],
$c
[
'authentication_service'
],
$c
[
'router'
]
->
pathFor
(
'user.login'
),
$c
[
'router'
]
->
pathFor
(
'user.logout.sso'
),
$c
[
'flash'
],
$c
[
'logger'
]
);
};
$events
=
$container
[
'events'
];
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$app
,
$container
)
{
$container
[
SchSync\Middleware\CreateUser
::
class
]
=
function
(
$c
)
{
return
new
SchSync\Middleware\CreateUser
(
$c
[
'authentication_service'
],
$c
[
'router'
]
->
pathFor
(
'user.login'
),
$c
[
'router'
]
->
pathFor
(
'user.logout.sso'
),
$c
[
'flash'
],
$c
[
'logger'
]
);
};
$container
[
SchSync\Middleware\CreateSchool
::
class
]
=
function
(
$c
)
{
return
new
SchSync\Middleware\CreateSchool
(
$c
[
'ldap'
],
$c
[
SchMM\FetchUnit
::
class
],
$c
[
'authentication_service'
],
$c
[
'router'
]
->
pathFor
(
'user.login'
),
$c
[
'router'
]
->
pathFor
(
'user.logout.sso'
),
$c
[
'flash'
],
$c
[
'logger'
]
);
};
$container
[
'router'
]
->
getNamedRoute
(
'user.login.sso'
)
->
add
(
SchSync\Middleware\CreateSchool
::
class
)
->
add
(
SchSync\Middleware\CreateUser
::
class
);
});
$events
(
'on'
,
'bootstrap'
,
function
()
use
(
$container
)
{
foreach
(
$container
[
'router'
]
->
getRoutes
()
as
$route
)
{
if
(
'user.login.sso'
===
$route
->
getName
())
{
$route
->
add
(
SchSync\Middleware\CreateUser
::
class
)
->
add
(
SchSync\Middleware\CreateSchool
::
class
);
break
;
}
}
},
-
10
);
};
module/sch_sync/src/Middleware/CreateSchool.php
View file @
16e3778b
...
...
@@ -113,6 +113,7 @@ class CreateSchool
$school
=
R
::
findOne
(
'school'
,
'registry_no = ?'
,
[
$registryNo
]);
try
{
if
(
!
$school
)
{
R
::
begin
();
$school
=
R
::
dispense
(
'school'
);
$school
->
registry_no
=
$unit
[
'registry_no'
];
$school
->
name
=
$unit
[
'name'
];
...
...
@@ -128,10 +129,17 @@ class CreateSchool
$school
->
eduadmin_id
=
$unit
[
'edu_admin_id'
];
$school
->
created
=
time
();
$school
->
creator
=
$identity
->
mail
;
R
::
store
(
$school
);
$school_id
=
R
::
store
(
$school
);
$this
->
logger
->
info
(
sprintf
(
'School %s imported from MM to database'
,
$registryNo
),
[
'creator'
=>
$identity
->
mail
]);
$user
=
R
::
load
(
'user'
,
$identity
->
id
);
$user
->
school_id
=
$school_id
;
R
::
store
(
$user
);
$this
->
logger
->
info
(
sprintf
(
'Set school %s to user %s'
,
$registryNo
,
$identity
->
mail
));
R
::
commit
();
}
}
catch
(
\
Exception
$e
)
{
R
::
rollback
();
$this
->
logger
->
error
(
sprintf
(
'Problem inserting school %s form MM in database'
,
$registryNo
));
$this
->
logger
->
debug
(
'Exception'
,
[
$e
->
getMessage
(),
$e
->
getTraceAsString
()]);
...
...
module/sch_sync/src/Middleware/CreateUser.php
View file @
16e3778b
...
...
@@ -15,12 +15,12 @@ use Psr\Http\Message\ServerRequestInterface as Request;
use
Psr\Log\LoggerInterface
;
use
RedBeanPHP\R
;
use
Slim\Flash\Messages
;
use
Zend\Authentication\AuthenticationService
Interface
;
use
Zend\Authentication\AuthenticationService
;
class
CreateUser
{
/**
* @var AuthenticationService
Interface
* @var AuthenticationService
*/
private
$authService
;
...
...
@@ -45,7 +45,7 @@ class CreateUser
private
$logger
;
public
function
__construct
(
AuthenticationService
Interface
$authService
,
AuthenticationService
$authService
,
$userErrorRedirectUrl
,
$ssoLogoutUrl
,
Messages
$flash
,
...
...
@@ -84,7 +84,18 @@ class CreateUser
));
}
$user
->
last_login
=
time
();
R
::
store
(
$user
);
$user_id
=
R
::
store
(
$user
);
$identityClass
=
get_class
(
$identity
);
$newIdentity
=
new
$identityClass
(
$user_id
,
$user
->
uid
,
$user
->
mail
,
$user
->
display_name
,
$user
->
office_name
,
$user
->
authentication_source
);
$this
->
authService
->
getStorage
()
->
write
(
$newIdentity
);
}
catch
(
\
Exception
$e
)
{
$this
->
authService
->
clearIdentity
();
$this
->
flash
->
addMessage
(
...
...
module/schools/src/Action/Index.php
View file @
16e3778b
...
...
@@ -25,6 +25,12 @@ class Index
public
function
__invoke
(
Request
$req
,
Response
$res
,
array
$args
=
[])
{
return
$this
->
view
->
render
(
$res
,
'schools/index.twig'
);
$identity
=
$req
->
getAttribute
(
'identity'
);
$user
=
\
RedBeanPHP\R
::
load
(
'user'
,
$identity
->
id
);
$school
=
$user
->
school
;
return
$this
->
view
->
render
(
$res
,
'schools/index.twig'
,
[
'school'
=>
$school
->
export
(),
]);
}
}
module/schools/templates/schools/index.twig
View file @
16e3778b
...
...
@@ -124,24 +124,7 @@
<div
class=
"col-xs-12 school-container"
>
{%
block
schoolContent
%}
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent pulvinar tincidunt
odio, vel pretium mauris imperdiet at. In tempor fermentum enim, euismod posuere
purus venenatis sit amet. Sed tincidunt, sapien et varius congue, orci urna rutrum
magna, in porttitor tellus ante nec quam. Praesent non ante commodo, ornare tellus
ut, commodo dolor. Aliquam id laoreet est, sed efficitur erat. Nunc orci diam,
fringilla eu hendrerit sit amet, mollis a risus. Nullam aliquet nisi aliquam ipsum
scelerisque, at convallis augue convallis. In placerat lorem eget lectus maximus,
sed mattis arcu efficitur. Nunc in magna ac neque eleifend sagittis. Quisque non
eros id nibh faucibus posuere. Fusce ut lorem laoreet lacus fermentum tempus at a
ante. Suspendisse luctus libero vel varius fermentum. Suspendisse nec metus odio.
</p>
<p>
In sapien urna, interdum nec sollicitudin vitae, efficitur et elit. Aliquam erat
volutpat. Aenean a nisl non quam hendrerit condimentum. Sed rhoncus posuere nulla,
vel aliquam orci imperdiet ullamcorper. Morbi vel lacus sem. Donec sit amet eros
eros. Donec sit amet vestibulum nunc. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Fusce interdum congue nibh accumsan
convallis. Curabitur sit amet orci efficitur, luctus metus ut, euismod enim. Aenean
ultricies arcu nisi, sit amet finibus risus posuere nec.
</p>
{{
school.name
}}
{%
endblock
%}
</div>
</div>
...
...
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