-
Notifications
You must be signed in to change notification settings - Fork 3
Project Listing Page #35
Changes from all commits
b10a2df
7d18779
2e7a7cf
0dc5ebd
61c50bf
571afbf
5f1aefd
f7b0e68
23071bf
4421d7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"""Project controller module.""" | ||
|
||
from tg import expose | ||
|
||
from acmwebsite.lib.base import BaseController | ||
from acmwebsite.model import DBSession, Project | ||
|
||
|
||
class ProjectsController(BaseController): | ||
"""Root controller for listing all projects""" | ||
|
||
@expose('acmwebsite.templates.projects') | ||
def index(self): | ||
return dict(page='projects', projects=DBSession.query(Project).all()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
from acmwebsite.controllers.meeting import MeetingsController | ||
from acmwebsite.controllers.schedule import ScheduleController | ||
from acmwebsite.controllers.survey import SurveysController | ||
from acmwebsite.controllers.project import ProjectsController | ||
|
||
from sqlalchemy.sql import functions | ||
|
||
|
@@ -51,6 +52,7 @@ class RootController(BaseController): | |
schedule = ScheduleController() | ||
error = ErrorController() | ||
contact = ContactController() | ||
projects = ProjectsController() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Individual projects should probably be located at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's continue use of short URLs even if Sumner does not like it... better for Emails, and looks better too. Sorry Sumner. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jackrosenthal, fine by me. Still doesn't matter here, this PR only deals with the project listing page. From what I can see, we agree on this URL scheme:
I think the real question is how to implement this. I think worst case scenario we have to add a CC: @samsartor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was mainly thinking about future work on #40. Maybe we should eventually rename |
||
|
||
def _before(self, *args, **kw): | ||
tmpl_context.project_name = "acmwebsite" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
"""Project model module.""" | ||
|
||
from sqlalchemy.orm import relationship | ||
from sqlalchemy import Table, ForeignKey, Column, UniqueConstraint | ||
from sqlalchemy.types import Integer, Unicode | ||
|
||
from depot.fields.sqlalchemy import UploadedFileField | ||
from depot.fields.specialized.image import UploadedImageWithThumb | ||
|
||
from acmwebsite.model import DeclarativeBase, metadata, User | ||
|
||
team_table = Table( | ||
'team', | ||
metadata, | ||
Column('user_id', Integer(), ForeignKey('tg_user.user_id'), nullable=False), | ||
Column('project_id', Integer(), ForeignKey('projects.id'), nullable=False), | ||
UniqueConstraint('user_id', 'project_id'), | ||
) | ||
|
||
|
||
class Project(DeclarativeBase): | ||
__tablename__ = 'projects' | ||
|
||
# Fields | ||
id = Column(Integer, autoincrement=True, primary_key=True) | ||
team_members = relationship(User, secondary=team_table, back_populates='projects') | ||
name = Column(Unicode(1024), unique=True, nullable=False) | ||
description = Column(Unicode(4096)) | ||
website = Column(Unicode(512)) | ||
repository = Column(Unicode(512)) | ||
video_url = Column(Unicode(512)) | ||
image = Column(UploadedFileField(upload_type=UploadedImageWithThumb)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,27 @@ | ||
(function($){ | ||
var last_query = ""; | ||
$("#ml-username").on("change keyup paste", function(){ | ||
if ($("#ml-username").val().indexOf("@") >= 0) { | ||
$("#ml-username").val($("#ml-username").val().replace(/\@.*$/g, "")); | ||
alert("Only a Mines username is required, not a full email address."); | ||
(function($) { | ||
var last_query = ""; | ||
$("#ml-username").on("change keyup paste", function() { | ||
if ($("#ml-username").val().indexOf("@") >= 0) { | ||
$("#ml-username").val($("#ml-username").val().replace(/\@.*$/g, "")); | ||
alert("Only a Mines username is required, not a full email address."); | ||
} | ||
if ($("#ml-username").val() != last_query && $("#ml-username").val().length > 1) { | ||
last_query = $("#ml-username").val(); | ||
$.getJSON("https://mastergo.mines.edu/mpapi/uid/" + encodeURIComponent($("#ml-username").val()), function(data) { | ||
if (data["result"] == "success") { | ||
$("#ml-fullname").val(data["attributes"]["first"] + " " + data["attributes"]["sn"]); | ||
$(".ml-fullname-warn").fadeIn(); | ||
} | ||
if ($("#ml-username").val() != last_query && $("#ml-username").val().length > 1) { | ||
last_query = $("#ml-username").val(); | ||
$.getJSON("https://mastergo.mines.edu/mpapi/uid/" + encodeURIComponent($("#ml-username").val()), function(data) { | ||
if (data["result"] == "success") { | ||
$("#ml-fullname").val(data["attributes"]["first"] + " " + data["attributes"]["sn"]); | ||
$(".ml-fullname-warn").fadeIn(); | ||
} | ||
else { | ||
$("#ml-fullname").val(""); | ||
$(".ml-fullname-warn").fadeOut(); | ||
} | ||
}); | ||
else { | ||
$("#ml-fullname").val(""); | ||
$(".ml-fullname-warn").fadeOut(); | ||
} | ||
}); | ||
}); | ||
} | ||
}); | ||
|
||
$('#mailinglist-form').submit(function() { | ||
$(this).find("button[type='submit']").prop('disabled',true); | ||
}); | ||
$('#mailinglist-form').submit(function() { | ||
$(this).find("button[type='submit']").prop('disabled',true); | ||
}); | ||
|
||
})(jQuery); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,22 @@ | ||
$(document).ready(function() { | ||
function change_theme(theme_name) { | ||
$('#bs-css').attr('href', '/css/bootstrap.' + theme_name + '.min.css'); | ||
$('#toggle-theme').text('Too ' + theme_name + '?'); | ||
} | ||
function change_theme(theme_name) { | ||
$('#bs-css').attr('href', '/css/bootstrap.' + theme_name + '.min.css'); | ||
$('#toggle-theme').text('Too ' + theme_name + '?'); | ||
} | ||
|
||
$('#toggle-theme').click(function (event) { | ||
event.preventDefault(); | ||
$.get("/toggle_theme", change_theme, "text"); | ||
}); | ||
$('#toggle-theme').click(function (event) { | ||
event.preventDefault(); | ||
$.get("/toggle_theme", change_theme, "text"); | ||
}); | ||
|
||
$(".vupdate").on("change keyup paste", function() { | ||
$(this).attr("value", $(this).val()); | ||
}); | ||
$(".vupdate").on("change keyup paste", function() { | ||
$(this).attr("value", $(this).val()); | ||
}); | ||
|
||
$('input[name="first_time"]').change(function() { | ||
checked = this.checked; | ||
$('.on-first-time').each(function() { | ||
if (checked) { $(this).fadeIn() } else { $(this).fadeOut() } | ||
}); | ||
$('input[name="first_time"]').change(function() { | ||
checked = this.checked; | ||
$('.on-first-time').each(function() { | ||
if (checked) { $(this).fadeIn() } else { $(this).fadeOut() } | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<html py:strip="" | ||
xmlns:py="http://genshi.edgewall.org/" | ||
xmlns:xi="http://www.w3.org/2001/XInclude"> | ||
|
||
<py:extends href="master.xhtml" /> | ||
|
||
<head py:block="head" py:strip="True"> | ||
<title>Mines ACM - Projects</title> | ||
</head> | ||
|
||
<body py:block="body" py:strip="True"> | ||
<h1 class="page-header">Projects</h1> | ||
<div py:for="project in projects" class="project-list-item panel panel-default"> | ||
<div class="panel-heading"> | ||
<h2 py:content="project.name" class="panel-title project-title" /> | ||
</div> | ||
<div class="panel-body"> | ||
<div class="row"> | ||
<div class="col-md-3"> | ||
<img py:if="project.image" src="${project.image.url}" class="project-image" /> | ||
</div> | ||
|
||
<div class="col-md-9"> | ||
<ul py:if="project.repository or project.website or project.video" | ||
class="list-inline project-links"> | ||
<li py:if="project.repository"> | ||
<a href="${project.repository}" target="_blank">${h.fa_icon('code-fork')} Repository</a> | ||
</li> | ||
<li py:if="project.website"> | ||
<a href="${project.website}" target="_blank">${h.fa_icon('globe')} Website</a> | ||
</li> | ||
<li py:if="project.video_url"> | ||
<a href="${project.video_url}" target="_blank">${h.fa_icon('video-camera')} Video</a> | ||
</li> | ||
</ul> | ||
<p py:content="h.markdown(project.description)" /> | ||
<p> | ||
<b>Contributors:</b> | ||
<ul> | ||
<li py:for="tm in project.team_members"> | ||
<a href="${tg.url('/u/{}'.format(tm.user_name))}" py:content="tm.display_name" /> | ||
</li> | ||
</ul> | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will there ever be the possibility of having a page for separate projects? If yes, the OO style thing we did with the meetings/surverys might be a good choice.
Not priority... something we eventually might consider. Can be done way after this has been merged...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. That's why I had this as a separate controller. It's kinda dumb right now, but in the future, I can definitely see eventually having a page for each project (for example, it may include more details about the project and/or additional media such as screenshots). I think is should be pretty easy to add on a
ProjectController
for the individual projects with this setup.