Anonymous avatar Anonymous committed 4e91e86 Merge

Code for preview.

Comments (0)

Files changed (24)

packageindex/forms.py

 from repoparsers.parsers import parse
 
 class AddPackageForm(forms.ModelForm):
+    checkout_url = forms.CharField(label="Repository url")
 
     class Meta:
         model = STPackage
         self.repo_data = parse(self.cleaned_data["checkout_url"])
         if not self.repo_data:
             raise forms.ValidationError("Cannot find repository.")
+        if not "Sublime Text" in self.repo_data["description"]:
+            raise forms.ValidationError("Cannot find 'Sublime Text' in description.")
         else:
             # we need to return the actual data for this field
             # if everything's all right.

packageindex/migrations/0001_initial.py

+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding model 'STPackage'
+        db.create_table('packageindex_stpackage', (
+            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+            ('name', self.gf('django.db.models.fields.CharField')(max_length=250)),
+            ('slug', self.gf('django.db.models.fields.SlugField')(unique=True, max_length=250, db_index=True)),
+            ('checkout_url', self.gf('django.db.models.fields.URLField')(unique=True, max_length=1000)),
+            ('repository_type', self.gf('django.db.models.fields.IntegerField')()),
+            ('description', self.gf('django.db.models.fields.TextField')(max_length=1000, blank=True)),
+        ))
+        db.send_create_signal('packageindex', ['STPackage'])
+
+
+    def backwards(self, orm):
+        
+        # Deleting model 'STPackage'
+        db.delete_table('packageindex_stpackage')
+
+
+    models = {
+        'packageindex.stpackage': {
+            'Meta': {'object_name': 'STPackage'},
+            'checkout_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '1000'}),
+            'description': ('django.db.models.fields.TextField', [], {'max_length': '1000', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'repository_type': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '250', 'db_index': 'True'})
+        }
+    }
+
+    complete_apps = ['packageindex']

packageindex/migrations/0002_auto__add_field_stpackage_asset_type.py

+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Adding field 'STPackage.asset_type'
+        db.add_column('packageindex_stpackage', 'asset_type', self.gf('django.db.models.fields.IntegerField')(default=4), keep_default=False)
+
+
+    def backwards(self, orm):
+        
+        # Deleting field 'STPackage.asset_type'
+        db.delete_column('packageindex_stpackage', 'asset_type')
+
+
+    models = {
+        'packageindex.stpackage': {
+            'Meta': {'object_name': 'STPackage'},
+            'asset_type': ('django.db.models.fields.IntegerField', [], {'default': '4'}),
+            'checkout_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '1000'}),
+            'description': ('django.db.models.fields.TextField', [], {'max_length': '1000', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'repository_type': ('django.db.models.fields.IntegerField', [], {}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '250', 'db_index': 'True'})
+        }
+    }
+
+    complete_apps = ['packageindex']

packageindex/migrations/0003_auto__del_field_stpackage_asset_type__add_field_stpackage_resource_typ.py

+# encoding: utf-8
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        
+        # Deleting field 'STPackage.asset_type'
+        db.delete_column('packageindex_stpackage', 'asset_type')
+
+        # Adding field 'STPackage.resource_type'
+        db.add_column('packageindex_stpackage', 'resource_type', self.gf('django.db.models.fields.IntegerField')(default=4), keep_default=False)
+
+
+    def backwards(self, orm):
+        
+        # Adding field 'STPackage.asset_type'
+        db.add_column('packageindex_stpackage', 'asset_type', self.gf('django.db.models.fields.IntegerField')(default=4), keep_default=False)
+
+        # Deleting field 'STPackage.resource_type'
+        db.delete_column('packageindex_stpackage', 'resource_type')
+
+
+    models = {
+        'packageindex.stpackage': {
+            'Meta': {'object_name': 'STPackage'},
+            'checkout_url': ('django.db.models.fields.URLField', [], {'unique': 'True', 'max_length': '1000'}),
+            'description': ('django.db.models.fields.TextField', [], {'max_length': '1000', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '250'}),
+            'repository_type': ('django.db.models.fields.IntegerField', [], {}),
+            'resource_type': ('django.db.models.fields.IntegerField', [], {'default': '4'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '250', 'db_index': 'True'})
+        }
+    }
+
+    complete_apps = ['packageindex']
Add a comment to this file

packageindex/migrations/__init__.py

Empty file added.

packageindex/models.py

     (GITHUB, 'GITHUB'),
 )
 
+THEME, PACKAGE, TOOL, OTHER, UNDEFINED = range(5)
+RESOURCE_TYPE = (
+    (THEME,"THEME"),
+    (PACKAGE,"PACKAGE"),
+    (TOOL,"TOOL"),
+    (OTHER,"OTHER"),
+    (UNDEFINED,"UNDEFINED"),
+)
+
 class STPackage(models.Model):
     """
     Represents a Sublime Text resource.
     checkout_url = models.URLField(max_length=1000, unique=True, verify_exists=False)
     repository_type = models.IntegerField(choices=REPO_TYPE)
     description = models.TextField(max_length=1000, blank=True)
+    resource_type = models.IntegerField(choices=RESOURCE_TYPE, default=UNDEFINED)
 
     def __unicode__(self):
         return self.name

packageindex/tests.py

 from packageindex.views import search_packages
 
 class PackageIndexViews(TestCase):
+
     def test_search_packages(self):
 
+        STPackage.objects.create(
+                        name="Powershell",
+                        slug="XXX",
+                        description="XXX",
+                        checkout_url="XXX",
+                        repository_type=0,
+                        resource_type=0,
+                        )
         c = Client()
         response = c.get("/packages/search/?search=powershell")
-
         self.assertEquals(len(response.context["results_list"]), 1)
 
-
     def test_add_package_fail(self):
-
+        # TODO: We need to bypass recaptcha to do this.
         c = Client()
         response = c.post("/packages/add/", {
                                             "name": "one",
                                             "checkout_url": "two",
-                                            "description":"three"
+                                            "description":"three",
+                                            "recaptcha_response_field":"dummy",
+                                            "recaptcha_challenge_field":"dummy",
                                             }
                         )
-        self.assertFormError(response=response, form="form", field="checkout_url", errors="Cannot locate rss feed.")
+        self.assertFormError(response=response, form="form", field="checkout_url", errors="Cannot find repository.")
         self.assertTemplateUsed(response=response, template_name="add_package.html")
 
     def test_add_package_succeed(self):
         c = Client()
         response = c.post("/packages/add/", {
                                             "name": "stindex",
-                                            "checkout_url": "http://bitbucket.org/guillermooo/stindex/rss",
-                                            "description":"Some text here."
+                                            "checkout_url": "http://bitbucket.org/guillermooo/sublimemodelines",
+                                            "description":"Some text here.",
+                                            "recaptcha_response_field":"dummy",
+                                            "recaptcha_challenge_field":"dummy",
                                             },
                             follow=True
                         )
 
-        self.assertRedirects(response=response, expected_url="/packages/stindex/")
+        self.assertRedirects(response=response, expected_url="/packages/sublimemodelines/")

packageindex/urls.py

 from django.views.generic.list_detail import object_detail
 from views import show_all_packages
 from django.views.generic.simple import redirect_to
+from django.conf import settings
 
 live_packages = {
     'queryset': STPackage.objects.all(),

packageindex/views.py

 from django.db.models import Q
 from recaptcha.client import captcha
 import socket
+from django.conf import settings
 
 def show_all_packages(request, page):
     live_packages = {
     if request.method == 'GET':
         search_term = request.GET.get('search', '')
 
-        print search_term
-        print request.GET
-
         # TODO: look for search term in NAME and DESCRIPTION
         return object_list(request,
                     queryset=STPackage.objects.filter(
     if request.method == 'POST':
         form = forms.AddPackageForm(data=request.POST)
 
+
         recaptcha_user_response = request.POST["recaptcha_response_field"]
         recaptcha_challenge_field = request.POST["recaptcha_challenge_field"]
-        r = captcha.submit(recaptcha_challenge_field,
-                            recaptcha_user_response,
-                            "6LcsL70SAAAAAHjpjI0R8ydYuYzQGv9Y2KTb-T4c",
-                            socket.gethostbyname(request.META["SERVER_NAME"]))
+        passed_recaptcha = True
+        if settings.RECAPTCHA_ENABLED:
+            r = captcha.submit(recaptcha_challenge_field,
+                                recaptcha_user_response,
+                                "6LcsL70SAAAAAHjpjI0R8ydYuYzQGv9Y2KTb-T4c",
+                                socket.gethostbyname(request.META["SERVER_NAME"]))
+            passed_recaptcha = r.is_valid
 
-        if r.is_valid:
+        if passed_recaptcha:
             if form.is_valid():
-                p = form.save(commit=False)
-                # We've cached repo_data after passing validation. This data is
-                # collected automatically by the repo parser.
-                # TODO: is this a bad practice?
-                p.__dict__.update(form.repo_data)
-                p.save()
 
-                # TODO: send a message along to the user: "Just added!"
-                return redirect(p.get_absolute_url())
+                existing = STPackage.objects.filter(slug=form.repo_data["slug"])
+                if not existing:
+                    p = form.save(commit=False)
+                    # We've cached repo_data after passing validation. This data is
+                    # collected automatically by the repo parser.
+                    # TODO: is this a bad practice?
+                    p.__dict__.update(form.repo_data)
+                    p.save()
+
+                    # TODO: send a message along to the user: "Just added!"
+                    return redirect(p.get_absolute_url())
+                else:
+                    return redirect(existing[0].get_absolute_url())
         else:
             return render_to_response("add_package.html",
                                 {"form": form, "captcha_error": "&error=%s" % r.error_code },

repoparsers/parsers.py

 import urlparse
 import json
 
+REST_API_MAP = {
+    "bitbucket_repo_info": "https://api.bitbucket.org/1.0/repositories/%s/%s/",
+    "github_repo_info": "https://github.com/api/v2/json/repos/show/%s/%s/",
+}
+
 def get_repo_by_name(user, slug):
     a = "https://api.bitbucket.org/1.0/repositories/%s/%s/" % (user, slug)
     f = urllib.urlopen(a)
     except ValueError:
         return {}
 
+def get_git_repo_by_name(user, slug):
+    a = "http://github.com/api/v2/json/repos/show/%s/%s/" % (user, slug)
+    f = urllib.urlopen(a)
+    try:
+        j = json.load(f)
+        return {
+            "name": j['repository']['name'],
+            "description": j['repository']['description'],
+            "checkout_url": "http://github.com/%s/%s/" % (user, slug),
+            "slug": slug,
+            "repository_type": 0,
+        }
+    except ValueError:
+        return {}
 
 def parse_bb_url(url):
     prefix = "http://bitbucket.org/"
 
 def parse(url):
     parsed = urlparse.urlparse(url)
-    if parsed.hostname.lower() == 'bitbucket.org':
-        data = parsed.path.split("/")
-        return get_repo_by_name(data[1], data[2])
-    else:
+
+    try:
+        if parsed.hostname.lower() == 'bitbucket.org':
+            data = parsed.path.split("/")
+            return get_repo_by_name(data[1], data[2])
+        elif parsed.hostname.lower() == "github.com":
+            data = parsed.path.split("/")
+            return get_git_repo_by_name(data[1], data[2])
+        else:
+            return {}
+    except AttributeError:
         return {}
 
 if __name__ == '__main__':
-    print parse("http://bitbucket.org/guillermooo/uberselection/")
+    print parse("http://bitbucket.org/guillermooo/uberselection/")
+    print parse("http://github.com/schacon/grit")
 Pygments==1.3.1
 Sphinx==1.0b2
 docutils==0.6
-ipython==0.10
-pyreadline==1.5.dev-r0
 django==1.2.3
 recaptcha-client==1.0.5
 import os
 
 DEBUG = True
+RECAPTCHA_ENABLED = True # Set to False when TESTING!
 TEMPLATE_DEBUG = DEBUG
 
 ADMINS = (
     # Uncomment the next line to enable the admin:
     'django.contrib.admin',
     'packageindex',
+    # Add this at the end.
+    'south',
 )

static_media/main.css

+body {
+    font-family: Arial;
+    font-size: 14pt;
+    padding-left: 1em;
+}
+
+
+/* Navigation top-left. */
+ul.nav {
+    padding: 0;
+    margin-bottom: 1em;
+    margin-left: 0;
+}
+
+.nav li {
+    display: inline;
+/*    margin-right: .50em;*/
+}
+
+.nav span.sep {
+    padding-left: 0.25em;
+    padding-right: 0.25em;
+}
+
+
+/* Footer */
+#footer {
+    margin-top: 2em;
+    padding-top: 0.5em;
+    border-top: 1px solid gray;
+}
+
+.search {
+    font-size: 25px;
+}
+
+.search input {
+    font-size: 25px;
+}
+
+.add_form {
+    font-size: 20px;
+}
+
+.add_form input {
+    font-size: 20px;
+}
+
+
+p.checkout_url {
+    font-family: Consolas, Courier New, sans;
+}
+
+
+/* Misc. */
+p.search_help {
+    font-size: small;
+    color: gray;
+}
+
+p.goal {
+    font-size: 20px;
+    margin-top: 2em;
+    margin-bottom: 2em;
+}
+
+p.appeal {
+    font-size: 20px;
+    margin-top: 1.5em;
+    margin-bottom: 3em;
+}

static_media/test.html

-<html>
-<head>
-    <title>Some test</title>
-</head>
-<body>
-    <p>Testing something.</p>
-</body>
-</html>

templates/404.html

+<html>
+<head>
+    <title>Page Not Found - 404</title>
+</head>
+<body>
+    <h1>404 Error - Page Not Found</h1>
+</body>
+</html>

templates/500.html

+<html>
+<head>
+    <title>Server Error - 500</title>
+</head>
+<body>
+    <h1>500 Error - Server Error</h1>
+</body>
+</html>

templates/add_package.html

-<html>
-<head>
-    <title>List of Packages</title>
-    <script type="text/javascript">
+{% extends "base.html" %}
+{% block title %}{{ block.super }} Add Resource{% endblock %}
+
+{% block extrahead %}<script type="text/javascript">
      var RecaptchaOptions = {
         theme : 'clean'
      };
  </script>
-</head>
-<body>
-<h1>Add a new package</h1>
+ {% endblock %}
 
-{% if captcha_error %}
-  <p>Wrong answer to recaptcha.</p>
-{% endif %}
+{% block content%}
+<h1>Add New Resource</h1>
 
-<form action="" method="post">{% csrf_token %}
+<p>Resources are mainly packages and themes for the <a href="http://sublimetext.com">Sublime Text</a> editor, but they can also be scripts or anything of value for Sublime Text users.
+</p>
+
+<p>Resources must meet two requirements:</p>
+<ul>
+  <li>They must be hosted on a public repository (Bitbucket or Github).</li>
+  <li>Their description field must include the phrase "Sublime Text".</li>
+</ul>
+
+<form class="add_form" action="" method="post">{% csrf_token %}
     {{ form.as_p }}
 
+    {% if captcha_error %}
+      <p class="recaptcha_error_warning">Ooops! Wrong answer to recaptcha. Try again, please.</p>
+    {% endif %}
     <script type="text/javascript"
      src="http://www.google.com/recaptcha/api/challenge?k=6LcsL70SAAAAAFHQaf7jxN8L9h4FaeKXNrV16Kog{{ captcha_error }}" >
   </script>
      <input type="hidden" name="recaptcha_response_field"
          value="manual_challenge">
   </noscript>
-    <input type="submit" value="Submit" />
+    <input type="submit" value="Add new resource" />
 </form>
-</body>
-</html>
+{% endblock content %}

templates/base.html

+<!DOCTYPE HTML>
 <html>
     <head>
-        <title>{% block title %}Sublime Text Info{% endblock %}</title>
+        <title>{% block title %}Sublime Text Info -{% endblock %}</title>
+        <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.8.1/build/base/base-min.css">
+        <link rel="stylesheet" type="text/css" href="/site_media/main.css" />
+        {% block extrahead %}{% endblock %}
     </head>
 
     <body>
         <ul class="nav">
             <li><a href="/">Home</a></li>
-            <li><a href="/packages/">Packages</a></li>
-            <li><a href="/docs/index.html">Documentation</a></li>
+            <li><span class="sep"> | </span><a href="/packages/">All Resources</a></li>
+            <li><span class="sep"> | </span><a href="/docs/index.html">Sublime Text Help</a></li>
 <!--             <li><a href="/faq/">FAQ</a></li> -->
 <!--             <li><a href="/about/">About</a></li> -->
         </ul>
         {% block content %}
         {% endblock %}
 
-    <hr/>
-    <p>(c) 2010 Guillermo López-Anglada</p>
+    <p id="footer">&copy; 2010 guillermooo</p>
     </body>
 </html>

templates/index.html

 	{% extends "base.html" %}
-	{% block title %}Sublime Text Info - Resources For Sublime Text Users {% endblock %}
+	{% block title %}{{ block.super }} Resources For Sublime Text Users{% endblock %}
 
 	{% block content %}
-	<p class="goal">Add features to and learn to use the <a href="http://www.sublimetext.com">Sublime Text</a> editor.<p>
+	<p class="goal">Resources for <a href="http://www.sublimetext.com">Sublime Text</a> users: packages, themes, documentation and more!<p>
 
-	<form name="search" action="/packages/search/" method="get">
-		<label for="search_box">Search packages:</label>
+	<form class="search" name="search" action="/packages/search/" method="get">
 		<input type="text" name="search" id="search_box" autofocus="autofocus" />
 		<input type="submit" value="Search" />
+		<p class="search_help">For documentation, go to <a href="/docs/">Sublime Text Help</a> first.
 	</form>
-	<p><a href="/packages/add/">Add a package</a></p>
+	<p class="appeal">Know something cool you want to share? <a href="/packages/add/">Add a resource</a>!</p>
 	{% endblock content %}

templates/package_detail.html

 {% extends "base.html" %}
-{% block title %}Package detail - {{ package.name }}{% endblock title %}
+{% block title %}{{ block.super }} Resource: {{ package.name }}{% endblock title %}
 
 {% block content %}
-	<h1>Sublime Text Package: {{ package.name }}</h1>
-    <p>{{ package.description }}</p>
-    <p>{{ package.get_checkout_command }}</p>
-    <p><a href="">How do I install this package?</a></p>
-    <a href="{{ package.checkout_url }}">Go to repository</a>
+	<h1>{{ package.name }}</h1>
+    <p class="description">{{ package.description }}</p>
+    <p class="checkout_url">{{ package.get_checkout_command }}</p>
+    <p class="how_to"><a href="">How do I install this package?</a></p>
+    <p class="go_to_repo"><a href="{{ package.checkout_url }}">Go to repository</a></p>
 {% endblock content %}

templates/package_list.html

 {% extends "base.html" %}
-{% block title %}List of Packages{% endblock %}
+{% block title %}{{ block.super }} All Resources{% endblock %}
 
 {% block content %}
-	<form name="search" action="/packages/search/" method="get">
-		<label for="search_box">Search packages:</label>
+	<form class="search" name="search" action="/packages/search/" method="get">
 		<input type="text" name="search" id="search_box" autofocus="autofocus" />
 		<input type="submit" value="Search" />
 	</form>
-	<hr>
+
 	{% for package in packages_list %}
-		<a href={{ package.get_absolute_url }}><strong>{{ package.name }}</strong></a>
-		<p><em>{{ package.description }}</em></p>
+		<div class="resource">
+			<p class="url"><a href="{{ package.get_absolute_url }}"><strong>{{ package.name }}</strong></a></p>
+			<p class="description">{{ package.description }}</p>
+		</div>
 	{% endfor %}
 
 	<p>

templates/search_results.html

 {% extends "base.html" %}
-{% block title %}Results for your search{% endblock title %}
+{% block title %}{{ block.super }} Search Results{% endblock title %}
 
 {% block content %}
-	<form name="search" action="." method="get">
-		<label for="search_box">Search packages:</label>
+	<form class="search" name="search" action="." method="get">
 		<input type="text" name="search" id="search_box" autofocus="autofocus" />
 		<input type="submit" value="Search" />
 	</form>
-	<h3>Search Results</h3>
 	{% for package in results_list %}
-		<p><a href="{{ package.get_absolute_url }}"><strong>{{ package.name }}</strong></a><br>
-			{{ package.description }}</p>
+		<div class="resource">
+			<p><a href="{{ package.get_absolute_url }}"><strong>{{ package.name }}</strong></a></p>
+			<p class="description">{{ package.description }}</p>
+		</div>
 	{% endfor %}
 
 	<p>
     (r'^packages/', include('stindex.packageindex.urls')),
     (r'^docs/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'C:/Users/guillermo/Dev/www/stindex-dev/stindex-branches/stindex/sublimehelp/_build/html/'}),
 )
+
+
+urlpatterns += patterns('',
+    (r'^site_media/(?P<path>.*)$', 'django.views.static.serve',
+        {'document_root': 'C:/Users/guillermo/Dev/www/stindex-dev/stindex/static_media/'}),
+    )
 import sys
 import os
+import time
 
 my_parent = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
 sys.path.append(my_parent)
     except IntegrityError, e:
         print "Duplicated, not importing: %s" % p
     print "="*80
+    time.sleep(0.5)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.