Commit 91d58e76 by aagusti

captcha berubah nama file jadi png

1 parent b7afeeb8
env_base/bin/activate
\ No newline at end of file
......@@ -9,6 +9,7 @@ from pyramid.httpexceptions import (
HTTPSeeOther)
from pyramid.i18n import TranslationStringFactory
from pyramid.interfaces import IRoutesMapper
from pyramid.response import Response
from pyramid.view import view_config
from opensipkd.base import get_params
......@@ -42,7 +43,7 @@ def not_found(request):
@view_config(context=HTTPInternalServerError, renderer='templates/500.pt')
def internal_server_error(request):
return {}
# response = Response('Internal error')
# response = Response('Terjadi kesahala')
# response.status_int = 500
# return response
......
import os
import re
from datetime import datetime
from dateutil.relativedelta import relativedelta
from opensipkd.tools.captcha import get_captcha
from pyramid.httpexceptions import HTTPFound
from .. import DBSession, get_params
from opensipkd.tools import dmy, dmy_to_date, get_settings
from opensipkd.tools import dmy, dmy_to_date, get_settings, get_ext
import colander
from deform import (widget, Form, ValidationFailure, )
from email.utils import parseaddr
from opensipkd.tools.buttons import btn_save, btn_cancel, btn_close, btn_delete
from ..models import User
class BaseView(object):
def __init__(self, request):
......@@ -94,7 +99,7 @@ class BaseView(object):
self.jenis = 'jenis' in self.params and self.params[
'jenis'] or self.jenis
self.ses['jenis'] = self.jenis
self.list_route = ''
self.list_route = 'home'
self.list_col_defs = ""
self.list_cols = ""
self.list_buttons = 'btn_view, btn_add, btn_edit, btn_delete, ' \
......@@ -114,7 +119,9 @@ class BaseView(object):
self.home = self.req.route_url('home')[:-1]
self.buttons = None
self.headers = None
self.bindings = None
self.bindings = {}
self.autocomplete = 'on'
# self.captcha = ""
def route_list(self, msg=None, error=""):
if msg:
......@@ -133,12 +140,12 @@ class BaseView(object):
def get_form(self, class_form, row=None, buttons=(btn_save, btn_cancel), **bindings):
buttons = self.buttons and self.buttons or buttons
bindings = self.bindings and self.bindings or bindings
schema = class_form(validator=self.form_validator)
schema = class_form(validator=self.form_validator) #
schema = schema.bind(request=self.req, **bindings)
schema.request = self.req
if row:
schema.deserialize(row)
return Form(schema, buttons=buttons)
return Form(schema, buttons=buttons, autocomplete=self.autocomplete)
def session_failed(self, session_name):
r = dict(form=self.req.session[session_name])
......@@ -187,7 +194,8 @@ class BaseView(object):
return self.route_list()
form = self.before_add(form)
table = self.get_item_table()
return dict(form=form.render(), table=table and table.render() or None, scripts=self.form_scripts)
return dict(form=form.render(), table=table and table.render() or None,
scripts=self.form_scripts)
def before_save(self, row, values):
return row
......@@ -196,6 +204,7 @@ class BaseView(object):
pass
def save(self, values, user, row=None):
self.ses["old_email"] = user and user.email or None
if not row:
row = self.table()
row.created = datetime.now()
......@@ -246,7 +255,6 @@ class BaseView(object):
row = self.query_id().first()
if not row:
return self.id_not_found()
form = self.get_form(self.edit_schema)
if request.POST:
if 'save' in request.POST:
......@@ -301,3 +309,36 @@ def email_validator(node, value):
name, email = parseaddr(value)
if not email or email.find('@') < 0:
raise colander.Invalid(node, 'Invalid email format')
class Store(dict):
def preview_url(self, name):
return ""
store = Store()
reg_exts = ['.png', '.jpg', '.pdf', '.jpeg']
def image_validator(node, value):
ext = get_ext(value["filename"])
if ext not in reg_exts:
raise colander.Invalid(node, f'Extension harus salahsatu dari {reg_exts}')
username_re = re.compile('^[a-z0-9_]{6,16}$', re.IGNORECASE)
def user_name_validator(node, value):
if not username_re.match(value):
raise colander.Invalid(node,
'Value must be between 6 and 16 characters and can only contain uppercase and lowercase alphanumeric characters or an underscore')
def need_captcha():
is_captcha = get_params("reg_captcha")
return is_captcha == '1' or is_captcha == "True" or is_captcha=="true" or is_captcha == True
def get_url_captcha(request):
captcha = get_captcha(request)
return os.path.join(request.route_url('home'),'captcha',captcha)
\ No newline at end of file
......@@ -27,36 +27,29 @@ Link dalam module registrasi:
5. Form Upload template
"""
import os
import re
from email.utils import parseaddr
import colander
from deform import (Form, widget, ValidationFailure, Button, FileData)
from opensipkd.base import get_params
from opensipkd.tools import get_settings, get_ext, Upload
from deform import (widget, ValidationFailure, Button, FileData)
from opensipkd.tools import Upload
from opensipkd.tools.captcha import get_captcha
from pyramid.httpexceptions import HTTPFound
from pyramid.i18n import TranslationStringFactory
from pyramid.view import view_config
from ziggurat_foundations.models.services.user import UserService
from opensipkd.base.views.user import insert as save_user
from opensipkd.base import get_params
from opensipkd.base.views.user import insert as save_user, email_validator
from opensipkd.base.views.user_login import send_email_security_code
from .user_group import save as save_groups
from ..models import User, DBSession, Partner, Group, UserGroup
from . import widget_os
from .base_views import store, image_validator, need_captcha, get_url_captcha
from ..models import User, DBSession, Partner, UserGroup
from ..views import BaseView
_ = TranslationStringFactory('user')
def email_validator(node, value):
name, email = parseaddr(value)
if not email or email.find('@') < 0:
raise colander.Invalid(node, 'Invalid email format')
class NamaSchema(colander.Schema):
class AddSchema(colander.Schema):
nama = colander.SchemaNode(
colander.String(),
oid="nama")
......@@ -78,109 +71,37 @@ class NamaSchema(colander.Schema):
validator=email_validator,
oid="email")
class Store(dict):
def preview_url(self, name):
return ""
store = Store()
reg_exts = ['.png', '.jpg', '.pdf', '.jpeg']
username_re = re.compile('^[a-z0-9_]{6,16}$', re.IGNORECASE)
def user_name_validator(node, value):
if not username_re.match(value):
raise colander.Invalid(node,
'Value must be between 6 and 16 characters and can only contain uppercase and lowercase alphanumeric characters or an underscore')
def id_card_validator(node, value):
ext = get_ext(value["filename"])
if ext not in reg_exts:
raise colander.Invalid(node, f'Extension harus salahsatu dari {reg_exts}')
class RegSchema(colander.Schema):
user_name = colander.SchemaNode(
colander.String(),
validator=user_name_validator,
# colander.Length(max=16, max_err='Maximum ${max} Digit',
# min=6, min_err='Minimimum ${min} Digit'),
oid="user_name")
kode = colander.SchemaNode(
colander.String(),
validator=colander.Length(max=18, max_err='Maximum ${max} Digit',
min=15, min_err='Minimimum ${min} Digit'),
title="No.Identitas/NIK",
oid="kode")
detail = NamaSchema()
doc_id_card = colander.SchemaNode(
FileData(),
widget=widget.FileUploadWidget(store),
validator=id_card_validator)
# captcha = colander.SchemaNode(
# colander.String(),
# oid="captcha")
def after_bin(self, schema, kwargs):
request = kwargs["request"]
if get_params('reg_idcard') != '1':
del self["doc_id_card"]
if get_params('reg_captcha') != '1':
del self["captcha"]
class RegEditSchema(colander.Schema):
user_name = colander.SchemaNode(
colander.String(),
widget=widget.TextInputWidget(readonly=True),
missing=colander.drop,
oid="user_name")
kode = colander.SchemaNode(
colander.String(),
widget=widget.TextInputWidget(readonly=True),
title="No.Identitas/NIK",
missing=colander.drop,
oid="kode")
detail = NamaSchema()
password = colander.SchemaNode(
colander.String(),
widget=widget.PasswordWidget(size=20),
# validator = user_name_validator,
title="Password",
oid="password")
id = colander.SchemaNode(
colander.Integer(),
missing=colander.drop,
widget=widget.HiddenWidget(readonly=True),
)
# doc_id_card = colander.SchemaNode(
# FileData(),
# widget=widget.String())
def after_bin(self, schema, kwargs):
request = kwargs["request"]
self.kode["widget"] = widget.TextInputWidget(readonly=True)
if "kode" not in request.params:
self.kode["widget"] = widget.TextInputWidget()
if "email" in request.params:
self.detail.email["widget"] = widget.TextInputWidget(readonly=True)
self.detail.email["missing"] = colander.drop
if request.get_params('reg_id_card') != '0':
del self["doc_id_card"]
# def user_name(user_name):
# return User.get_by_identity(email)
def after_bind(self, schema, kw):
request = kw.get("request")
is_id_card = get_params('reg_idcard')
if is_id_card == '1' or is_id_card == "True" or is_id_card == "true":
self["kode"] = colander.SchemaNode(
colander.String(),
widget=widget.TextInputWidget(),
title="No.Identitas/NIK",
# missing=colander.drop,
oid="kode")
self["doc_id_card"] = colander.SchemaNode(
FileData(),
widget=widget.FileUploadWidget(store),
title="Photo Identitas",
validator=image_validator)
if not request.user and need_captcha():
self["captcha"] = colander.SchemaNode(
colander.String(),
widget=widget_os.CaptchaWidget(url=get_url_captcha(request)),
oid="captcha", title="Captcha")
if request.user and request.user.id:
self["password"] = colander.SchemaNode(
colander.String(),
widget=widget.PasswordWidget()
, oid="password", title="Password")
class EditSchema(AddSchema):
pass
def user_found(identity):
......@@ -213,281 +134,182 @@ def show_error(request, msg):
# 3. Cek NIK (kode) pada Partner jika ada dan Partner.id beda reject
def form_validator(form, value):
value.update(value['detail'])
form_exc = colander.Invalid(form, '')
def err_captcha():
msg = 'Captcha harus diisi'
raise colander.Invalid(form['captcha'], msg)
def err_email():
exc = colander.Invalid(
form['detail']['email'], 'e-mail %s sudah ada yang menggunakan' % value['email'])
raise exc
def err_user():
raise colander.Invalid(
form['user_name'], 'User name %s sudah ada yang menggunakan' % value['user_name'])
def err_nik():
raise colander.Invalid(
form['kode'], 'NIK %s sudah ada yang menggunakan' % value['kode'])
def err_login():
raise colander.Invalid(
form, 'User atau Password tidak sesuai')
request = form.request
# Check user_name
detail = value['detail']
email = detail['email']
is_logged = form.request.user
if 'user_name' in value:
user_name = value["user_name"]
# Check Data User
user = user_found(user_name)
def reg_buttons():
btn_register = Button(name='save', css_class='btn-success', type="submit", title="Register")
btn_cancel = Button(name='batal', css_class='btn-primary', type="submit")
return btn_cancel, btn_register
class Registrasi(BaseView):
def __init__(self, request):
super(Registrasi, self).__init__(request)
self.autocomplete = "off"
self.buttons = reg_buttons()
self.add_schema = AddSchema
self.edit_schema = EditSchema
self.table = User
self.list_route = "home"
def form_validator(self, form, value):
form_exc = colander.Invalid(form, '')
def err_captcha():
msg = 'Captcha harus diisi'
raise colander.Invalid(form['captcha'], msg)
def err_email():
exc = colander.Invalid(
form['email'], 'e-mail %s sudah ada yang menggunakan' % value['email'])
raise exc
def err_user():
raise colander.Invalid(
form['user_name'], 'User name %s sudah ada yang menggunakan' % value['user_name'])
def err_nik():
if "kode" in form:
raise colander.Invalid(
form['kode'], 'NIK %s sudah ada yang menggunakan' % value['kode'])
else:
raise colander.Invalid(
form['mobile'], 'Mobile %s sudah ada yang menggunakan' % value['kode'])
def err_login():
raise colander.Invalid(
form["password"], 'User atau Password tidak sesuai')
request = form.request
is_logged = form.request.user
email = value["email"]
if "user_name" not in value or not value["user_name"]:
value["user_name"] = value["mobile"]
if 'user_name' in value:
# Check Data User
user_name = value["user_name"]
user = user_found(user_name)
if user and not is_logged:
err_user()
if user and is_logged:
if user.id != is_logged.id:
err_user()
user = user_found(email)
if user and not is_logged:
err_user()
err_email()
if user and is_logged:
if user.id != is_logged.id:
err_user()
err_email()
user = user_found(email)
if user and not is_logged:
err_email()
if user and is_logged:
if user.id != is_logged.id:
err_email()
# Check Data Partner
if request.user:
q = DBSession.query(Partner).filter_by(email=request.user.email)
partner = q.first()
else:
partner = None
# Check Data Partner
if 'id' in request.matchdict:
uid = request.matchdict['id']
q = DBSession.query(Partner).filter_by(id=uid)
partner = q.first()
else:
partner = None
found = email_found_partner(email)
if partner:
if found and found.id != partner.id:
found = email_found_partner(email)
if partner:
if found and found.id != partner.id:
err_email()
elif found:
err_email()
elif found:
err_email()
# CEK NIK apakah Sudah Ada di tabel Partner?
if 'kode' in value:
found_nik = nik_found(value['kode'])
if partner:
if found_nik and found_nik.id != partner.id:
if "kode" not in value or not value["kode"]:
value["kode"] = value["mobile"]
if 'kode' in value:
found_nik = nik_found(value['kode'])
if partner:
if found_nik and found_nik.id != partner.id:
err_nik()
elif found_nik:
err_nik()
elif found_nik:
err_nik()
# Check Captcha jika registrasi
if not request.user:
if get_params("reg_captcha") == '1':
# Check Captcha jika registrasi
if not request.user and need_captcha():
if 'captcha' not in value or not value['captcha'] \
or 'captcha' not in request.session or not request.session['captcha']:
err_captcha()
captcha = 'captcha' in value and value['captcha'].upper() or None
if not captcha or captcha != request.session['captcha']:
del request.session["captcha"]
err_captcha()
# Cek Old Password
if 'password' in value:
user = form.request.user
if not user or not UserService.check_password(user, value['password']):
err_login()
def get_form(request, class_form, buttons=('batal', 'simpan'),
validator=form_validator):
schema = class_form(validator=validator)
schema = schema.bind(request=request)
schema.request = request
return Form(schema, buttons=buttons)
def save_partner(values, row=None):
if not row:
row = Partner()
row.is_vendor = 0
row.is_customer = 1
row.status = 0
row.from_dict(values)
DBSession.add(row)
DBSession.flush()
return row
def save_request(values, request, row=None):
values.update(values['detail'])
# disini yang di cek id partner
if 'id' in request.matchdict:
values['id'] = request.matchdict['id']
# Check registrant apakah sudah punya user atau belum
if request.user:
# Jika sudah punya user masukan ke group esppt
user = request.user
user_group = UserGroup.get_by_user(user)
if user.email != values['email']:
user.email = values['email']
DBSession.add(user)
DBSession.flush()
values['status'] = 1
else:
# Jika Tidak Tambahkan User dan Kirim Email
user_ = dict(user_name=values['user_name'],
email=values['email'])
user, remain = save_user(request, user_)
# if not external identity send security code
if 'external' not in request.session or not request.session['external']:
send_email_security_code(
request, user, remain, 'Welcome new user', 'email-new-user',
'email-new-user.tpl')
data = dict(email=user.email)
ts = _(
'user-added',
default='${email} berhasil ditambahkan dan email untuk ubah ' \
'kata kunci sudah dikirim.',
mapping=data)
request.session.flash(ts)
if row:
if row.email == row.kode:
values['kode'] = values['email']
else:
if 'kode' not in values and not values['kode']:
values['kode'] = values['email']
values['user_id'] = user.id
row = save_partner(values, row)
##Untuk SIMKEL##
# settings = get_settings()
# if 'default_group' in settings:
# groups = settings['default_group'].split(',')
# for group in groups:
# group_data = Group.query_group_name(group).first()
# if not group_data:
# raise custom_error(-1, "Group Not Found.")
# data = dict(group_id=group_data.id,
# user_id=user.id)
# save_groups(data, None)
return row
def route_list(request):
return HTTPFound(location=request.route_url('home'))
if 'password' in value:
user = form.request.user
if not user or not UserService.check_password(user, value['password']):
err_login()
def before_save(self, row, values):
if "doc_id_card" not in values or not values["doc_id_card"]:
return row
def reg_buttons():
btn_register = Button(name='register', css_class='btn-success', type="submit")
btn_cancel = Button(name='batal', css_class='btn-primary', type="submit")
path = get_params('reg_folder', '/tmp/registrasi')
if not os.path.exists(path):
os.makedirs(path)
return btn_cancel, btn_register
upload = Upload(path)
values["doc_id_card"] = upload.save(self.req, 'upload')
row.doc_id_card = values["doc_id_card"]
return row
def before_edit(self, form):
partner = DBSession.query(Partner). \
join(User, Partner.email == User.email). \
filter(User.id == self.req.user.id).first()
if partner:
values = {}
for f in ["nama", "alamat_1", "alamat_2", "mobile", "email"]:
values[f] = hasattr(partner, f) and getattr(partner, f) or ""
form.set_appstruct(values)
return form
def after_save(self, row, values):
if "old_email" in self.ses and self.ses["old_email"]:
email = self.ses["old_email"]
del self.ses["old_email"]
else:
email = row.email
partner = Partner.query_email(email).first()
if not partner:
partner = Partner()
partner.is_vendor = 0
partner.is_customer = 1
partner.status = 0
class RegistrasiAdd(BaseView):
@view_config(route_name='register', renderer='templates/register.pt')
partner.from_dict(values)
DBSession.add(partner)
DBSession.flush()
return row
@view_config(route_name='register', renderer='templates/form_input.pt')
def view_add(self):
request = self.req
self.bindings = dict(user=None)
if request.user:
return HTTPFound(location=request.route_url("profile"))
form = get_form(request, RegSchema, reg_buttons())
captcha = get_params("reg_captcha") and get_captcha(request) or None
if request.POST:
if 'register' in request.POST:
# input_file = request.POST['upload'].file
# filename = request.POST['upload'].filename.lower()
# ext = get_ext(filename).lower()
# raise ext
controls = request.POST.items()
try:
controls = form.validate(controls)
except ValidationFailure as e:
form.set_appstruct(e.cstruct)
return dict(form=form.render(), captcha=captcha, scripts="")
values = dict(controls)
path = get_params('reg_folder', '/tmp/registrasi')
if not os.path.exists(path):
os.makedirs(path)
upload = Upload(path)
values["doc_id_card"] = upload.save(request, 'upload')
save_request(values, request)
request.session.flash('Registrasi Sukses.')
if 'captcha' in request.session:
del (request.session['captcha'])
return route_list(request)
# self.captcha = need_captcha() and get_captcha(request) or ""
return super(Registrasi, self).view_add()
values = {}
if request.user:
values['email'] = request.user.email
form.set_appstruct(values)
return dict(form=form.render(), captcha=get_captcha(request),
scripts="")
@view_config(route_name='profile', renderer='templates/register.pt',
@view_config(route_name='profile', renderer='templates/form_input.pt',
permission='view')
def es_reg_edt(self):
request = self.req
register_form = get_params("register_form")
self.bindings = dict(user=self.req.user)
if register_form:
return HTTPFound(location=request.route_url(register_form))
return super(Registrasi, self).view_edit()
ses = request.session
query = query_id(request)
row = query.first()
form = get_form(request, RegEditSchema)
if request.POST:
if 'simpan' in request.POST:
controls = request.POST.items()
try:
controls = form.validate(controls)
except ValidationFailure as e:
values = e.cstruct
values['kode'] = row.kode
form.set_appstruct(values)
return dict(form=form)
save_request(dict(controls), request, row)
request.session.flash('Sukses Update Profile.')
return route_list(request)
if row:
values = row.to_dict()
values['detail'] = row.to_dict()
else:
values = dict(detail=dict(email=request.user.email))
form.set_appstruct(values)
return dict(form=form.render(), captcha=get_captcha(request), scripts="")
def query_id(self):
return DBSession.query(User). \
filter(User.id == self.req.user.id)
########
# Edit #
########
def query_id(request):
return DBSession.query(Partner). \
join(User, Partner.email == User.email). \
filter(User.id == request.user.id)
def id_not_found(request):
msg = 'Register ID %s Tidak Ditemukan.' % request.matchdict['id']
request.session.flash(msg, 'error')
return route_list(request)
def id_not_found(self):
return
......@@ -12,7 +12,7 @@ from pyramid.view import view_config
from ziggurat_foundations.models.services.user import UserService
# from . import get_login_headers
from .register import mobile_found_partner, save_partner, nik_found
# from .register import mobile_found_partner, save_partner, nik_found
from .user_group import save as save_groups
from ..models import DBSession, Partner, Group, ExternalIdentity, User, ExternalIdentityService
from opensipkd.tools import get_settings
......
......@@ -105,6 +105,7 @@
<a href="#" class="dropdown-toggle txt-color-white" data-toggle="dropdown">My Account <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a style="text-transform:capitalize" href="${home}logout">${request.user.nice_username()} Logout</a></li>
<li><a style="text-transform:capitalize" href="${home}profile">Profile</a></li>
<li><a style="text-transform:capitalize" href="${home}password">Ubah password</a></li>
<li tal:condition="request.user.api_key">
<a style="text-transform:capitalize" href="${home}recreate-api-key">
......
......@@ -2,7 +2,7 @@
tal:define="home request.route_url('home')[:-1];">
<div metal:fill-slot="scripts">
<script>
<script tal:condition="${captcha}">
$(document).ready(function () {
$("#captcha").parent().prepend('<img style="height:30px; width:auto; margin-bottom:5px;'+
'" src="${home}/captcha/${captcha}.png">')
......@@ -14,7 +14,6 @@ tal:define="home request.route_url('home')[:-1];">
});
});
</script>
</div>
</html>
......@@ -114,7 +114,7 @@ def view_login(request):
return redirect_login(request, user)
elif 'register' in request.POST:
register_form = get_params("register_form", 'register-external')
register_form = get_params("register_form", 'register')
return HTTPFound(location=request.route_url(register_form))
elif 'login failed' in request.session:
......
......@@ -247,55 +247,23 @@ class CaptchaWidget(Widget):
If true, during deserialization, strip the value of leading
and trailing whitespace (default ``True``).
mask
A :term:`jquery.maskedinput` input mask, as a string.
a - Represents an alpha character (A-Z,a-z)
9 - Represents a numeric character (0-9)
* - Represents an alphanumeric character (A-Z,a-z,0-9)
All other characters in the mask will be considered mask
literals.
Example masks:
Date: 99/99/9999
US Phone: (999) 999-9999
US SSN: 999-99-9999
When this option is used, the :term:`jquery.maskedinput`
library must be loaded into the page serving the form for the
mask argument to have any effect. See :ref:`masked_input`.
mask_placeholder
The placeholder for required nonliteral elements when a mask
is used. Default: ``_`` (underscore).
"""
template = "opensipkd.base:views/widgets/captcha"
readonly_template = "opensipkd.base:views/widgets/captcha"
template = "opensipkd.base:views/widgets/captcha.pt"
readonly_template = "textinput"
strip = True
# mask = None
# mask_placeholder = "_"
requirements = ()
# def __init__(self, **kw):
# super(CaptchaWidget, self).__init__(**kw)
# if getattr(self, "mask", False):
# self.requirements = tuple(
# list(self.requirements) + [("jquery.maskedinput", None)]
# )
def __init__(self, **kw):
super(CaptchaWidget, self).__init__(**kw)
def serialize(self, field, cstruct, **kw):
if cstruct in (null, None):
cstruct = ""
readonly = kw.get("readonly", self.readonly)
template = readonly and self.readonly_template or self.template
# values = self.get_template_values(field, cstruct, kw)
return field.renderer(template, None)
values = self.get_template_values(field, cstruct, kw)
return field.renderer(template, **values)
def deserialize(self, field, pstruct):
if pstruct is null:
......
<span tal:define="name name|field.name;
css_class css_class|field.widget.css_class;
oid oid|field.oid;
captcha captcha|field.widget.captcha;
style style|field.widget.style;
url url|field.widget.url;
"
tal:omit-tag="">
<img style="height:30px; width:auto; margin-bottom:5px;" src="${url}">
<input type="text" name="${name}" value="${cstruct}"
tal:attributes="class string: form-control ${css_class or ''};
style style;
attributes|field.widget.attributes|{};"
id="${oid}"/>
<script type="text/javascript">
deform.addCallback(
'${oid}',
function (oid) {
$("#" + oid).parent().prepend('<img style="height:30px; width:auto; margin-bottom:5px;' +
'" src="${home}/captcha/${captcha}.png">')
$('#'+oid).on('input', function (evt) {
$(this).val(function (_, val) {
return val.toUpperCase();
});
});
});
</script>
</span>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!