add admin register

This commit is contained in:
Dario 2020-01-27 14:02:28 +01:00
parent 3b21cad114
commit 35d762541e
17 changed files with 510 additions and 15 deletions

View File

@ -18,6 +18,7 @@
#include "Error500Page.h"
#include "CheckTransactionPage.h"
#include "ResetPassword.h"
#include "RegisterAdminPage.h"
#include "DecodeTransactionPage.h"
@ -131,6 +132,11 @@ Poco::Net::HTTPRequestHandler* PageRequestHandlerFactory::createRequestHandler(c
pageRequestHandler->setProfiler(timeUsed);
return pageRequestHandler;
}
if (url_first_part == "/adminRegister") {
auto pageRequestHandler = new RegisterAdminPage(s);
pageRequestHandler->setProfiler(timeUsed);
return pageRequestHandler;
}
if(url_first_part == "/logout") {
sm->releaseSession(s);

View File

@ -0,0 +1,179 @@
#include "RegisterAdminPage.h"
#include "Poco/Net/HTTPServerRequest.h"
#include "Poco/Net/HTTPServerResponse.h"
#include "Poco/Net/HTMLForm.h"
#include "Poco/DeflatingStream.h"
#line 7 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
#include "../SingletonManager/SessionManager.h"
#include "Poco/Net/HTTPCookie.h"
#line 1 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp"
#include "../ServerConfig.h"
RegisterAdminPage::RegisterAdminPage(Session* arg):
SessionHTTPRequestHandler(arg)
{
}
void RegisterAdminPage::handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response)
{
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
bool _compressResponse(request.hasToken("Accept-Encoding", "gzip"));
if (_compressResponse) response.set("Content-Encoding", "gzip");
Poco::Net::HTMLForm form(request, request.stream());
#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
const char* pageName = "Admin Registrieren";
//auto sm = SessionManager::getInstance();
bool userReturned = false;
if(!form.empty()) {
userReturned = mSession->adminCreateUser(
form.get("register-first-name", ""),
form.get("register-last-name", ""),
form.get("register-email", "")
);
getErrors(mSession);
}
std::ostream& _responseStream = response.send();
Poco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, 1);
std::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;
responseStream << "\n";
// begin include header_old.cpsp
responseStream << "\n";
responseStream << "<!DOCTYPE html>\n";
responseStream << "<html>\n";
responseStream << "<head>\n";
responseStream << "<meta charset=\"UTF-8\">\n";
responseStream << "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n";
responseStream << "<title>Gradido Login Server: ";
#line 9 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp"
responseStream << ( pageName );
responseStream << "</title>\n";
responseStream << "<!--<link rel=\"stylesheet\" type=\"text/css\" href=\"css/styles.min.css\">-->\n";
responseStream << "<link rel=\"stylesheet\" type=\"text/css\" href=\"";
#line 11 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp"
responseStream << ( ServerConfig::g_php_serverPath );
responseStream << "/css/styles.css\">\n";
responseStream << "<style type=\"text/css\" >\n";
responseStream << ".grd_container\n";
responseStream << "{\n";
responseStream << " max-width:820px;\n";
responseStream << " margin-left:auto;\n";
responseStream << " margin-right:auto;\n";
responseStream << "}\n";
responseStream << "\n";
responseStream << "input:not([type='radio']) {\n";
responseStream << "\twidth:200px;\n";
responseStream << "}\n";
responseStream << "label:not(.grd_radio_label) {\n";
responseStream << "\twidth:80px;\n";
responseStream << "\tdisplay:inline-block;\n";
responseStream << "}\n";
responseStream << ".grd_container_small\n";
responseStream << "{\n";
responseStream << " max-width:500px;\n";
responseStream << "}\n";
responseStream << ".grd_text {\n";
responseStream << " max-width:550px;\n";
responseStream << " margin-bottom: 5px;\n";
responseStream << "}\n";
responseStream << ".dev-info {\n";
responseStream << "\tposition: fixed;\n";
responseStream << "\tcolor:grey;\n";
responseStream << "\tfont-size: smaller;\n";
responseStream << "\tleft:8px;\n";
responseStream << "}\n";
responseStream << ".grd-time-used { \n";
responseStream << " bottom:0;\n";
responseStream << "} \n";
responseStream << "\n";
responseStream << ".versionstring {\n";
responseStream << "\ttop:0;\n";
responseStream << "}\n";
responseStream << "</style>\n";
responseStream << "</head>\n";
responseStream << "<body>\n";
responseStream << "<div class=\"versionstring dev-info\">\n";
responseStream << "\t<p class=\"grd_small\">Login Server in Entwicklung</p>\n";
responseStream << "\t<p class=\"grd_small\">Alpha ";
#line 53 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\header_old.cpsp"
responseStream << ( ServerConfig::g_versionString );
responseStream << "</p>\n";
responseStream << "</div>\n";
// end include header_old.cpsp
responseStream << "\n";
responseStream << "<div class=\"grd_container\">\n";
responseStream << "\t<h1>Einen neuen Account anlegen</h1>\n";
responseStream << "\t";
#line 30 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
responseStream << ( getErrorsHtml() );
responseStream << "\n";
responseStream << "\t";
#line 31 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
if(!form.empty() && userReturned) { responseStream << "\n";
responseStream << "\t\t<div class=\"grd_text-max-width\">\n";
responseStream << "\t\t\t<div class=\"grd_text\">\n";
responseStream << "\t\t\t\tDie Anmeldung wird verarbeitet und es wird dem Benutzer eine Aktivierungs-E-Mail zugeschickt. \n";
responseStream << "\t\t\t</div>\n";
responseStream << "\t\t</div>\n";
responseStream << "\t";
#line 37 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
} else { responseStream << "\n";
responseStream << "\t<form method=\"POST\">\n";
responseStream << "\t\t\n";
responseStream << "\t\t<fieldset class=\"grd_container_small\">\n";
responseStream << "\t\t\t<legend>Account anlegen</legend>\n";
responseStream << "\t\t\t<p>Bitte gebe deine Daten um einen Account anzulegen</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<label for=\"register-first-name\">Vorname</label>\n";
responseStream << "\t\t\t\t<input id=\"register-first-name\" type=\"text\" name=\"register-first-name\" value=\"";
#line 45 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
responseStream << ( !form.empty() ? form.get("register-first-name") : "" );
responseStream << "\"/>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<label for=\"register-last-name\">Nachname</label>\n";
responseStream << "\t\t\t\t<input id=\"register-last-name\" type=\"text\" name=\"register-last-name\" value=\"";
#line 49 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
responseStream << ( !form.empty() ? form.get("register-last-name") : "" );
responseStream << "\"/>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t\t<p class=\"grd_small\">\n";
responseStream << "\t\t\t\t<label for=\"register-email\">E-Mail</label>\n";
responseStream << "\t\t\t\t<input id=\"register-email\" type=\"email\" name=\"register-email\" value=\"";
#line 53 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
responseStream << ( !form.empty() ? form.get("register-email") : "" );
responseStream << "\"/>\n";
responseStream << "\t\t\t</p>\n";
responseStream << "\t\t</fieldset>\n";
responseStream << "\t\t<input class=\"grd-form-bn grd-form-bn-succeed\" type=\"submit\" name=\"submit\" value=\"Anmelden\">\n";
responseStream << "\t\t\n";
responseStream << "\t</form>\n";
responseStream << "\t";
#line 59 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\registerAdmin.cpsp"
} responseStream << "\n";
responseStream << "</div>\n";
// begin include footer.cpsp
responseStream << "\t<div class=\"grd-time-used dev-info\">\n";
responseStream << "\t\t\t";
#line 2 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\footer.cpsp"
responseStream << ( mTimeProfiler.string() );
responseStream << "\n";
responseStream << "\t</div>\n";
responseStream << "</body>\n";
responseStream << "</html>";
// end include footer.cpsp
responseStream << "\n";
if (_compressResponse) _gzipStream.close();
}

View File

@ -0,0 +1,20 @@
#ifndef RegisterAdminPage_INCLUDED
#define RegisterAdminPage_INCLUDED
#include "Poco/Net/HTTPRequestHandler.h"
#include "SessionHTTPRequestHandler.h"
class RegisterAdminPage: public SessionHTTPRequestHandler
{
public:
RegisterAdminPage(Session*);
void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);
};
#endif // RegisterAdminPage_INCLUDED

View File

@ -0,0 +1,116 @@
#include "JsonCreateUser.h"
#include "Poco/URI.h"
#include "../SingletonManager/SessionManager.h"
#include "../SingletonManager/SingletonTaskObserver.h"
#include "../SingletonManager/ErrorManager.h"
Poco::JSON::Object* JsonCreateUser::handle(Poco::Dynamic::Var params)
{
int session_id = 0;
Poco::JSON::Object* result = new Poco::JSON::Object;
/*result->set("state", "debugging");
result->set("msg", "deactivate for debugging");
return result;
*/
if (params.isStruct()) {
session_id = params["session_id"];
//std::string miau = params["miau"];
}
else if (params.isVector()) {
try {
const Poco::URI::QueryParameters queryParams = params.extract<Poco::URI::QueryParameters>();
for (auto it = queryParams.begin(); it != queryParams.end(); it++) {
if (it->first == "session_id") {
session_id = stoi(it->second);
break;
}
}
//auto var = params[0];
}
catch (const std::invalid_argument& ia) {
result->set("state", "error");
result->set("msg", "error parsing query params, invalid argument: ");
result->set("details", ia.what());
return result;
}
catch (const std::out_of_range& oor) {
result->set("state", "error");
result->set("msg", "error parsing query params, Out of Range error: ");
result->set("details", oor.what());
return result;
}
catch (const std::logic_error & ler) {
result->set("state", "error");
result->set("msg", "error parsing query params, Logical error: ");
result->set("details", ler.what());
return result;
}
catch (Poco::Exception& ex) {
//printf("[JsonGetLogin::handle] exception: %s\n", ex.displayText().data());
result->set("state", "error");
result->set("msg", "error parsing query params, Poco Error");
result->set("details", ex.displayText());
return result;
}
}
if (session_id) {
auto sm = SessionManager::getInstance();
auto observer = SingletonTaskObserver::getInstance();
auto session = sm->getSession(session_id);
if (session) {
auto userNew = session->getNewUser();
auto user = session->getUser();
if (user.isNull()) {
result->set("state", "not found");
result->set("msg", "Session didn't contain user");
return result;
}
auto userModel = userNew->getModel();
if (userModel.isNull()) {
result->set("state", "not found");
result->set("msg", "user is empty");
return result;
}//*/
result->set("state", "success");
result->set("clientIP", session->getClientIp().toString());
try {
result->set("user", userNew->getJson());
}
catch (Poco::Exception ex) {
auto em = ErrorManager::getInstance();
em->addError(new ParamError("JsonGetLogin::handle", "poco exception calling userModel->getJson: ", ex.displayText().data()));
em->sendErrorsAsEmail();
}
catch (...) {
auto em = ErrorManager::getInstance();
em->addError(new Error("JsonGetLogin::handle", "generic exception calling userModel->getJson: "));
em->sendErrorsAsEmail();
}
result->set("Transaction.pending", session->getProcessingTransactionCount());
auto executing = observer->getTaskCount(userModel->getEmail(), TASK_OBSERVER_SIGN_TRANSACTION);
if (executing < 0) {
executing = 0;
}
result->set("Transaction.executing", executing);
//printf("pending: %d\n", session->getProcessingTransactionCount());
return result;
}
else {
result->set("state", "not found");
result->set("msg", "session not found");
return result;
}
}
else {
result->set("state", "error");
result->set("msg", "empty session id");
}
return result;
}

View File

@ -0,0 +1,16 @@
#ifndef __JSON_INTERFACE_JSON_CREATE_USER_
#define __JSON_INTERFACE_JSON_CREATE_USER_
#include "JsonRequestHandler.h"
class JsonCreateUser : public JsonRequestHandler
{
public:
Poco::JSON::Object* handle(Poco::Dynamic::Var params);
protected:
};
#endif // __JSON_INTERFACE_JSON_CREATE_USER_

View File

@ -16,6 +16,17 @@ Mit freundlichen Grüßen\n\
Dario, Gradido Server Admin\n\
"};
const static char EmailText_adminEmailVerification[] = { u8"\
Hallo [first_name] [last_name],\n\
\n\
Der Admin hat soeben ein Gradido Konto für dich mit dieser E-Mail angelegt.\n\
Bitte klicke zur Bestätigung auf den Link: [link]\n\
oder kopiere den obigen Link in Dein Browserfenster.\n\
\n\
Mit freundlichen Grüßen\n\
Dario, Gradido Server Admin\n\
"};
const static char EmailText_emailResetPassword[] = { u8"\
Hallo [first_name] [last_name],\n\
\n\
@ -77,6 +88,8 @@ Gradido Login Server\
Poco::Net::MediaType mt("text", "plain");
mt.setParameter("charset", "utf-8");
const char* messageTemplate = nullptr;
switch (mType) {
case EMAIL_DEFAULT:
mailMessage->addRecipient(adminRecipient);
@ -91,6 +104,7 @@ Gradido Login Server\
break;
case EMAIL_USER_VERIFICATION_CODE:
case EMAIL_ADMIN_USER_VERIFICATION_CODE:
if (userTableModel.isNull() || mUser->getModel()->getEmail() == "") {
addError(new Error(functionName, "no receiver email set for user email verification email"));
return false;
@ -102,9 +116,14 @@ Gradido Login Server\
mailMessage->addRecipient(Poco::Net::MailRecipient(Poco::Net::MailRecipient::PRIMARY_RECIPIENT, mUser->getModel()->getEmail()));
mailMessage->setSubject(langCatalog->gettext_str("Gradido: E-Mail Verification"));
messageTemplate = EmailText_emailVerification;
if (mType == EMAIL_ADMIN_USER_VERIFICATION_CODE) {
messageTemplate = EmailText_adminEmailVerification;
}
mailMessage->addContent(
new Poco::Net::StringPartSource(replaceUserNamesAndLink(
langCatalog->gettext(EmailText_emailVerification),
langCatalog->gettext(messageTemplate),
userTableModel->getFirstName(),
userTableModel->getLastName(),
mEmailVerificationCode->getLink()

View File

@ -27,6 +27,7 @@ namespace model {
EMAIL_DEFAULT,
EMAIL_ERROR,
EMAIL_USER_VERIFICATION_CODE,
EMAIL_ADMIN_USER_VERIFICATION_CODE,
EMAIL_USER_RESET_PASSWORD,
EMAIL_ADMIN_RESET_PASSWORD_REQUEST_WITHOUT_MEMORIZED_PASSPHRASE
};

View File

@ -135,6 +135,58 @@ Poco::AutoPtr<controller::EmailVerificationCode> Session::getEmailVerificationCo
return ret;
}
bool Session::adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email)
{
Profiler usedTime;
if (mNewUser->getModel()->getRole() != model::table::ROLE_ADMIN) {
addError(new Error(gettext("Benutzer"), gettext("Eingeloggter Benutzer ist kein Admin")));
return false;
}
auto sm = SessionManager::getInstance();
if (!sm->isValid(first_name, VALIDATE_NAME)) {
addError(new Error(gettext("Vorname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")));
return false;
}
if (!sm->isValid(last_name, VALIDATE_NAME)) {
addError(new Error(gettext("Nachname"), gettext("Bitte gebe einen Namen an. Mindestens 3 Zeichen, keines folgender Zeichen <>&;")));
return false;
}
if (!sm->isValid(email, VALIDATE_EMAIL)) {
addError(new Error(gettext("E-Mail"), gettext("Bitte gebe eine g&uuml;ltige E-Mail Adresse an.")));
return false;
}
// check if user with that email already exist
if (mNewUser->getModel()->isExistInDB("email", email)) {
addError(new Error(gettext("E-Mail"), gettext("F&uuml;r diese E-Mail Adresse gibt es bereits einen Account")));
return false;
}
auto newUser = controller::User::create(email, first_name, last_name);
updateTimeout();
auto newUserModel = newUser->getModel();
if (!newUserModel->insertIntoDB(true)) {
addError(new Error(gettext("Benutzer"), gettext("Fehler beim speichern!")));
return false;
}
auto emailVerificationCode = controller::EmailVerificationCode::create(newUserModel->getID(), model::table::EMAIL_OPT_IN_REGISTER);
if (!emailVerificationCode->getModel()->insertIntoDB(false)) {
addError(new Error(gettext("Email Verification Code"), gettext("Fehler beim speichern!")));
return false;
}
EmailManager::getInstance()->addEmail(new model::Email(emailVerificationCode, newUser, model::EMAIL_ADMIN_USER_VERIFICATION_CODE));
return true;
}
bool Session::createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password)
{
Profiler usedTime;

View File

@ -70,6 +70,10 @@ public:
// TODO: automatic redirect after some time, median profiled time for register
// TODO: register state: written into db, mails sended, update state only if new state is higher as old state
bool createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password);
// adminRegister without passwort
bool adminCreateUser(const std::string& first_name, const std::string& last_name, const std::string& email);
// TODO: check if email exist and if not, fake waiting on password hashing with profiled times of real password hashing
UserStates loadUser(const std::string& email, const std::string& password);
bool ifUserExist(const std::string& email);

View File

@ -34,7 +34,7 @@ namespace model {
~ElopageBuy();
// generic db operations
const char* getTableName() { return "elopage_buys"; }
const char* getTableName() const { return "elopage_buys"; }
std::string toString();

View File

@ -28,7 +28,7 @@ namespace model {
~EmailOptIn();
// generic db operations
const char* getTableName() { return "email_opt_in"; }
const char* getTableName() const { return "email_opt_in"; }
std::string toString();
inline Poco::UInt64 getCode() const { return mEmailVerificationCode; }

View File

@ -30,13 +30,15 @@ namespace model {
ModelBase() : mID(0), mReferenceCount(1) {}
virtual ~ModelBase();
virtual const char* getTableName() = 0;
virtual const char* getTableName() const = 0;
virtual std::string toString() = 0;
template<class T>
size_t updateIntoDB(const std::string& fieldName, const T& fieldValue );
template<class T>
size_t loadFromDB(const std::string& fieldName, const T& fieldValue);
template<class T>
bool isExistInDB(const std::string& fieldName, const T& fieldValue) const;
template<class WhereFieldType, class Tuple>
std::vector<Tuple> loadFromDB(const std::string& fieldName, const WhereFieldType& fieldValue, int expectedResults = 0);
template<class T1, class T2>
@ -90,6 +92,30 @@ namespace model {
return resultCount;
}
template<class T>
bool ModelBase::isExistInDB(const std::string& fieldName, const T& fieldValue) const
{
auto cm = ConnectionManager::getInstance();
Poco::Data::Statement select(cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER));
int id;
select << "SELECT " << "id "
<< " FROM " << getTableName()
<< " WHERE " << fieldName << " = ?"
, into(id), Poco::Data::Keywords::useRef(fieldValue);
try {
if (select.execute() == 1) {
return true;
}
}
catch (Poco::Exception& ex) {
/*lock();
addError(new ParamError(getTableName(), "mysql error by isExistInDB", ex.displayText().data()));
addError(new ParamError(getTableName(), "field name for select: ", fieldName.data()));
unlock();*/
}
return false;
}
template<class WhereFieldType, class Tuple>
std::vector<Tuple> ModelBase::loadFromDB(const std::string& fieldName, const WhereFieldType& fieldValue, int expectedResults)
{

View File

@ -38,7 +38,7 @@ namespace model {
~User();
// generic db operations
const char* getTableName() { return "users"; }
const char* getTableName() const { return "users"; }
std::string toString();

View File

@ -26,7 +26,7 @@ namespace model {
~UserRoles();
// generic db operations
const char* getTableName() { return "user_roles"; }
const char* getTableName() const { return "user_roles"; }
std::string toString();
inline int getUserId() const { return mUserId; }

View File

@ -77,8 +77,11 @@
<p>pubkey: <%= hex %></p>
<p>amount: <%= receiver.amount() %></p>
<% } %>
<% } else if(transactionBody.has_creation()) { %>
<% } else if(transactionBody.has_creation()) {
auto creation = transactionBody.creation();
%>
<h3>Creation</h3>
<p>pubkey: <%= creation.
<% } %>
<% } %>
</div>

View File

@ -52,11 +52,3 @@ label:not(.grd_radio_label) {
<p class="grd_small">Login Server in Entwicklung</p>
<p class="grd_small">Alpha <%= ServerConfig::g_versionString %></p>
</div>
<!--<nav class="grd-left-bar expanded" data-topbar role="navigation">
<div class="grd-left-bar-section">
<ul class="grd-no-style">
<li><a href="<%= ServerConfig::g_php_serverPath %>" class="grd-nav-bn">Startseite</a>
<li><a href="./account/logout" class="grd-nav-bn">Logout</a></li>
</ul>
</div>
</nav>-->

View File

@ -0,0 +1,61 @@
<%@ page class="RegisterAdminPage" %>
<%@ page form="true" %>
<%@ page compressed="true" %>
<%@ page baseClass="SessionHTTPRequestHandler" %>
<%@ page ctorArg="Session*" %>
<%@ header include="SessionHTTPRequestHandler.h" %>
<%!
#include "../SingletonManager/SessionManager.h"
#include "Poco/Net/HTTPCookie.h"
%>
<%%
const char* pageName = "Admin Registrieren";
//auto sm = SessionManager::getInstance();
bool userReturned = false;
if(!form.empty()) {
userReturned = mSession->adminCreateUser(
form.get("register-first-name", ""),
form.get("register-last-name", ""),
form.get("register-email", "")
);
getErrors(mSession);
}
%><%@ include file="header_old.cpsp" %>
<div class="grd_container">
<h1>Einen neuen Account anlegen</h1>
<%= getErrorsHtml() %>
<% if(!form.empty() && userReturned) {%>
<div class="grd_text-max-width">
<div class="grd_text">
Die Anmeldung wird verarbeitet und es wird dem Benutzer eine Aktivierungs-E-Mail zugeschickt.
</div>
</div>
<% } else { %>
<form method="POST">
<fieldset class="grd_container_small">
<legend>Account anlegen</legend>
<p>Bitte gebe die Benutzer-Daten ein um einen Account anzulegen</p>
<p class="grd_small">
<label for="register-first-name">Vorname</label>
<input id="register-first-name" type="text" name="register-first-name" value="<%= !form.empty() ? form.get("register-first-name") : "" %>"/>
</p>
<p class="grd_small">
<label for="register-last-name">Nachname</label>
<input id="register-last-name" type="text" name="register-last-name" value="<%= !form.empty() ? form.get("register-last-name") : "" %>"/>
</p>
<p class="grd_small">
<label for="register-email">E-Mail</label>
<input id="register-email" type="email" name="register-email" value="<%= !form.empty() ? form.get("register-email") : "" %>"/>
</p>
</fieldset>
<input class="grd-form-bn grd-form-bn-succeed" type="submit" name="submit" value="Anmelden">
</form>
<% } %>
</div>
<%@ include file="footer.cpsp" %>