diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..318bc5d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pyc +**/*.pyc +keys.py +.DS_Store \ No newline at end of file diff --git a/app.yaml b/app.yaml index 328e7a3..a272b2f 100644 --- a/app.yaml +++ b/app.yaml @@ -6,5 +6,9 @@ api_version: 1 handlers: - url: /dns.* script: dns.py +- url: /domains.* + script: domains.py +- url: /static + static_dir: static - url: .* script: main.py diff --git a/domains.py b/domains.py new file mode 100644 index 0000000..0cb14f7 --- /dev/null +++ b/domains.py @@ -0,0 +1,25 @@ +import wsgiref.handlers +from google.appengine.ext import webapp +from google.appengine.api import users +from google.appengine.ext.webapp import template + +from main import Domain + +class DomainsHandler(webapp.RequestHandler): + def get(self): + user = users.get_current_user() + if user: + domains = Domain.get_all_by_user(user) + logout_url = users.create_logout_url("/") + self.response.out.write(template.render('templates/domains.html', locals())) + else: + self.redirect('/') + + +def main(): + application = webapp.WSGIApplication([('/domains', DomainsHandler),], debug=True) + wsgiref.handlers.CGIHandler().run(application) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/main.py b/main.py index 264c1f2..93c9021 100755 --- a/main.py +++ b/main.py @@ -1,34 +1,31 @@ -#!/usr/bin/env python -# -# Copyright 2007 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - - - - import wsgiref.handlers - from google.appengine.ext import webapp from google.appengine.api import users from google.appengine.api import urlfetch from google.appengine.ext.webapp import template +from google.appengine.ext import db + +import urllib # These only work if your IP is allowed -ENOM_UID = 'fihn' -ENOM_PASS = '' +import keys +ENOM_UID = keys.enom_uid +ENOM_PASS = keys.enom_pass +ENOM_HOST = keys.enom_host +NS1 = 'ns1.domdori.com' +NS2 = 'ns2.domdori.com' + +class Domain(db.Model): + user = db.UserProperty(auto_current_user_add=True) + created = db.DateTimeProperty(auto_now_add=True) + updated = db.DateTimeProperty(auto_now=True) + name = db.StringProperty(required=True) + + @classmethod + def get_all_by_user(cls, user): + return cls.all().filter('user =', user) + def parse_response(body): return dict([kvp.split('=') for kvp in body.split('\r\n') if len(kvp) and not kvp[0] == ';']) @@ -36,6 +33,20 @@ def parse_response(body): class RegisterHandler(webapp.RequestHandler): def get(self): self.response.out.write(template.render('templates/main.html', locals())) + + def post(self): + domain = self.request.POST['domain'] + sld, tld = domain.split('.') + url = "http://%s/Interface.asp?command=Purchase&UID=%s&PW=%s&SLD=%s&TLD=%s&NS1=%s&NS2=%s" % (ENOM_HOST, ENOM_UID, ENOM_PASS, sld, tld, NS1, NS2) + resp = urlfetch.fetch(url) + resp = parse_response(resp.content) + if resp['RRPCode'] == '200': + d = Domain(name=domain) + d.put() + self.response.headers.add_header('Set-Cookie', 'flash=%s' % urllib.quote("You successfully registered %s!" % domain)) + self.redirect('/domains') + else: + self.response.out.write(resp['RRPText']) class MainHandler(webapp.RequestHandler): def get(self): @@ -54,7 +65,7 @@ def get(self): else: sld = domain tld = '@' - url = "http://resellertest.enom.com/interface.asp?Command=Check&UID=%s&PW=%s&SLD=%s&TLD=%s" % (ENOM_UID, ENOM_PASS, sld, tld) + url = "http://%s/interface.asp?Command=Check&UID=%s&PW=%s&SLD=%s&TLD=%s" % (ENOM_HOST, ENOM_UID, ENOM_PASS, sld, tld) resp = urlfetch.fetch(url) resp = parse_response(resp.content) domains = {} @@ -66,9 +77,12 @@ def get(self): domains[domain] = resp['RRPText'] self.response.out.write(str(domains)) +class SplashHandler(webapp.RequestHandler): + def get(self): + self.response.out.write("Be patient...") def main(): - application = webapp.WSGIApplication([('/', MainHandler), ('/check', CheckHandler), ('/register', RegisterHandler)], debug=True) + application = webapp.WSGIApplication([('/', SplashHandler), ('/main', MainHandler), ('/check', CheckHandler), ('/register', RegisterHandler)], debug=True) wsgiref.handlers.CGIHandler().run(application) diff --git a/static/js/jquery.cookie.js b/static/js/jquery.cookie.js new file mode 100644 index 0000000..6df1fac --- /dev/null +++ b/static/js/jquery.cookie.js @@ -0,0 +1,96 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/static/js/jquery.growl.js b/static/js/jquery.growl.js new file mode 100644 index 0000000..2174e2f --- /dev/null +++ b/static/js/jquery.growl.js @@ -0,0 +1,143 @@ +/* + * jQuery Growl plugin + * Version 1.0.2 (8/1/2009) + * @requires jQuery v1.3.2 or later + * + * Examples at: http://fragmentedcode.com/jquery-growl + * Copyright (c) 2008-2009 David Higgins + * + * Special thanks to Daniel Mota for inspiration: + * http://icebeat.bitacoras.com/mootools/growl/ + */ + +/* +USAGE: + + $.growl(title, msg); + $.growl(title, msg, image); + $.growl(title, msg, image, priority); + +THEME/SKIN: + +You can override the default look and feel by updating these objects: +$.growl.settings.displayTimeout = 4000; +$.growl.settings.noticeTemplate = '' + + '
' + + '
' + + '
' + + ' ' + + '

%title%

' + + '

%message%

' + + '
' + + '
' + + '
'; +$.growl.settings.noticeCss = { + position: 'relative' +}; + +To change the 'dock' look, and position: + +$.growl.settings.dockTemplate = '
'; +$.growl.settings.dockCss = { + position: 'absolute', + top: '10px', + right: '10px', + width: '300px' + }; + +The dockCss will allow you to 'dock' the notifications to a specific area +on the page, such as TopRight (the default) or TopLeft, perhaps even in a +smaller area with "overflow: scroll" enabled? +*/ + +(function($) { + +$.growl = function(title,message,image,priority) { notify(title,message,image,priority); } +$.growl.version = "1.0.2"; + +function create(rebuild) { + var instance = document.getElementById('growlDock'); + if(!instance || rebuild) { + instance = $(jQuery.growl.settings.dockTemplate).attr('id', 'growlDock').addClass('growl'); + if(jQuery.growl.settings.defaultStylesheet) { + $('head').append(''); + } + + } else { + instance = $(instance); + } + $('body').append(instance.css(jQuery.growl.settings.dockCss)); + return instance; +}; + +function r(text, expr, val) { + while(expr.test(text)) { + text = text.replace(expr, val); + } + return text; +}; + +function notify(title,message,image,priority) { + var instance = create(); + var html = jQuery.growl.settings.noticeTemplate; + if(typeof(html) == 'object') html = $(html).html(); + html = r(html, /%message%/, (message?message:'')); + html = r(html, /%title%/, (title?title:'')); + html = r(html, /%image%/, (image?image:jQuery.growl.settings.defaultImage)); + html = r(html, /%priority%/, (priority?priority:'normal')); + + var notice = $(html) + .hide() + .css(jQuery.growl.settings.noticeCss) + .fadeIn(jQuery.growl.settings.notice);; + + $.growl.settings.noticeDisplay(notice); + instance.append(notice); + $('a[rel="close"]', notice).click(function() { + notice.remove(); + }); + if ($.growl.settings.displayTimeout > 0) { + setTimeout(function(){ + jQuery.growl.settings.noticeRemove(notice, function(){ + notice.remove(); + }); + }, jQuery.growl.settings.displayTimeout); + } +}; + + +// default settings +$.growl.settings = { + dockTemplate: '
', + dockCss: { + position: 'fixed', + top: '10px', + right: '10px', + //width: '300px', + zIndex: 50000 + }, + noticeTemplate: + '
' + + '

%title%

' + + '

%message%

' + + '
', + noticeCss: { + opacity: .75, + backgroundColor: '#333333', + color: '#ffffff' + }, + noticeDisplay: function(notice) { + notice.css({'opacity':'0'}).fadeIn(jQuery.growl.settings.noticeFadeTimeout); + }, + noticeRemove: function(notice, callback) { + notice.fadeOut({opacity: '0', height: '0px'}, {duration:jQuery.growl.settings.noticeFadeTimeout, complete: callback}); + }, + noticeFadeTimeout: 'slow', + displayTimeout: 3500, + defaultImage: 'growl.jpg', + defaultStylesheet: null, + noticeElement: function(el) { + $.growl.settings.noticeTemplate = $(el); + } +}; +})(jQuery); \ No newline at end of file diff --git a/templates/_register.html b/templates/_register.html new file mode 100644 index 0000000..2148b57 --- /dev/null +++ b/templates/_register.html @@ -0,0 +1,46 @@ +
+ +
+
+ +
+ +
+ + + + + + + + + + + + +
\ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 753907c..9226e3a 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,9 +2,22 @@ {% block title %}domdori - domains done right{% endblock %} - + + + + + + - +