Changeset 98


Ignore:
Timestamp:
Apr 4, 2009, 6:41:25 PM (10 years ago)
Author:
gav
Message:

Installed help-balloons plugin.
Adjust security config to allow javascript and help-balloons folders.
Add "Repeat password" to change password.
Detailed Entry views, including only allow user to edit their own entries.
Adjust Entry constraints.
Add comments to layouts/main.gsp.
Work on TaskDetailed? view to show entry durations and allow editing.
Entry duration formatting to CSS and increased base font size to 14px.

Location:
trunk/src
Files:
11 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/application.properties

    r74 r98  
    11#utf-8
    2 #Sun Mar 15 21:57:51 EST 2009
     2#Fri Apr 03 23:02:58 EST 2009
     3plugins.help-balloons=1.2
    34app.version=0.1
    45plugins.acegi=0.5.1
  • trunk/src/grails-app/conf/SecurityConfig.groovy

    r73 r98  
    3636    '/css/*': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    3737    '/images/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
     38    '/js/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
     39    '/plugins/help-balloons-1.2/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    3840    '/login*': ['IS_AUTHENTICATED_ANONYMOUSLY'],
    3941    '/login/**': ['IS_AUTHENTICATED_ANONYMOUSLY'],
  • trunk/src/grails-app/controllers/AppCoreController.groovy

    r91 r98  
    2727        if (request.method == 'POST') {
    2828            def personInstance = Person.get(authenticateService.userDomain().id)
    29    
    30             personInstance.pass = params.pass
    31             personInstance.password = authenticateService.encodePassword(personInstance.pass)
    3229
    33             if (!personInstance.hasErrors() && personInstance.save()) {
    34                 //userCache.removeUserFromCache(personInstance.loginName)
    35                 flash.message = "Password changed successfully."
    36                 redirect(action:options)
     30            if(params.repeatPass == params.pass) {
     31                personInstance.pass = params.pass
     32                personInstance.password = authenticateService.encodePassword(personInstance.pass)
     33
     34                if (!personInstance.hasErrors() && personInstance.save()) {
     35                    //userCache.removeUserFromCache(personInstance.loginName)
     36                    flash.message = "Password changed successfully."
     37                    redirect(action:options)
     38                }
     39                else {
     40                    render(view:'changePassword',model:[personInstance:personInstance])
     41                }
    3742            }
    3843            else {
     44                flash.message = "Passwords must match."
     45//                 personInstance.addToErrors("Passwords must match.")
    3946                render(view:'changePassword',model:[personInstance:personInstance])
    40             }                         
     47            }
     48               
    4149        } 
    4250    }
  • trunk/src/grails-app/controllers/EntryDetailedController.groovy

    r91 r98  
    2828        def entryInstance = Entry.get( params.id )
    2929        if(entryInstance) {
    30             entryInstance.delete()
    31             flash.message = "Entry ${params.id} deleted"
    32             redirect(action:list)
     30            if(entryInstance.enteredBy.loginName == authenticateService.userDomain().loginName) {
     31                entryInstance.delete()
     32                flash.message = "Entry ${params.id} deleted"
     33                redirect(action:list)
     34            }
     35            else {
     36                flash.message = "You may only delete your own entries."
     37                redirect(action:show,id:entryInstance.id)
     38            }
     39
    3340        }
    3441        else {
     
    4047    def edit = {
    4148        def entryInstance = Entry.get( params.id )
    42 
    4349        if(!entryInstance) {
    44             flash.message = "Entry not found with id ${params.id}"
    45             redirect(action:list)
     50                flash.message = "Entry not found with id ${params.id}"
     51                redirect(action:list)
    4652        }
    4753        else {
    48             return [ entryInstance : entryInstance ]
     54
     55            if(entryInstance.enteredBy.loginName == authenticateService.userDomain().loginName) {
     56                return [ entryInstance : entryInstance ]
     57            }
     58            else {
     59                flash.message = "You may only edit your own entries."
     60                redirect(action:show,id:entryInstance.id)
     61            }
     62
    4963        }
    5064    }
     
    6983
    7084    def create = {
    71         def entryInstance = new Entry()
    72         entryInstance.properties = params
    73         return ['entryInstance':entryInstance]
     85        try {
     86            def taskInstance = Task.get(params.taskInstance.id)
     87            def entryInstance = new Entry()
     88            entryInstance.task = taskInstance
     89            return ['entryInstance':entryInstance]
     90        }
     91        catch(Exception e) {
     92            flash.message = "Please select a task, then 'Add Entry'"
     93            redirect(controller:"taskDetailed", action:"list")
     94        }
    7495    }
    7596
  • trunk/src/grails-app/domain/Entry.groovy

    r66 r98  
    1515        comment(blank:false,maxSize:500)
    1616        dateDone()
    17         durationHour(min:0)
     17        durationHour(min:0,max:16)
    1818        durationMinute(min:0,max:59)
    1919       
  • trunk/src/grails-app/i18n/messages.properties

    r73 r98  
    11person.pass.minSize.notmet=Password is less than the minimum size of [{3}]
    22person.pass.blank=Password cannot be blank
     3
     4entry.duration=Duration
     5entry.duration.help=The time (hh:mm) booked against this entry for date done.
    36
    47default.doesnt.match.message=Property [{0}] of class [{1}] with value [{2}] does not match the required pattern [{3}]
  • trunk/src/grails-app/views/appCore/changePassword.gsp

    r79 r98  
    3737                                        </tr>
    3838
     39                    <tr class="prop">
     40                        <td valign="top" class="name"><label for="repeatPass">Repeat password:</label></td>
     41                        <td valign="top" class="value">
     42                            <input type="password" id="repeatPass" name="repeatPass" />
     43                        </td>
     44                    </tr>
     45
    3946                                </tbody>
    4047                                </table>
  • trunk/src/grails-app/views/entryDetailed/create.gsp

    r92 r98  
    4242                                </td>
    4343                                <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'comment','errors')}">
    44                                     <textarea style="width:450px" rows="5" cols="40" name="comment">${fieldValue(bean:entryInstance, field:'comment')}</textarea>
     44                                    <textarea rows="5" cols="40" name="comment">${fieldValue(bean:entryInstance, field:'comment')}</textarea>
    4545                                </td>
    4646                            </tr>
     
    5757                            <tr class="prop">
    5858                                <td valign="top" class="name">
    59                                     <label for="durationHour">Duration Hour:</label>
     59                                    <label for="durationHour">Duration:</label>
    6060                                </td>
    61                                 <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'durationHour','errors')}">
    62                                     <input type="text" id="durationHour" name="durationHour" value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
    63                                 </td>
    64                             </tr>
    65                        
    66                             <tr class="prop">
    67                                 <td valign="top" class="name">
    68                                     <label for="durationMinute">Duration Minute:</label>
    69                                 </td>
    70                                 <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}">
    71                                     <input type="text" id="durationMinute" name="durationMinute" value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
    72                                 </td>
    73                             </tr>
    7461
    75                        
     62                                <td valign="top" class="value">
     63                                    <input class="duration ${hasErrors(bean:entryInstance,field:'durationHour','errors')}"
     64                                        type="text" id="durationHour" name="durationHour"
     65                                        value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
     66                                    :
     67                                    <input class="duration ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}"
     68                                        type="text" id="durationMinute" name="durationMinute"
     69                                        value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
     70                                    <g:helpBalloon code="entry.duration" />
     71                                </td>
     72                            </tr>
     73                     
    7674                            <tr class="prop">
    7775                                <td valign="top" class="name">
  • trunk/src/grails-app/views/entryDetailed/edit.gsp

    r92 r98  
    5252                                </td>
    5353                                <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'dateDone','errors')}">
    54                                     <g:datePicker name="dateDone" value="${entryInstance?.dateDone}" ></g:datePicker>
     54                                    <g:datePicker name="dateDone" value="${entryInstance?.dateDone}" precision="day"></g:datePicker>
    5555                                </td>
    5656                            </tr>
     
    5858                            <tr class="prop">
    5959                                <td valign="top" class="name">
    60                                     <label for="durationHour">Duration Hour:</label>
     60                                    <label for="durationHour">Duration:</label>
    6161                                </td>
    62                                 <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'durationHour','errors')}">
    63                                     <input type="text" id="durationHour" name="durationHour" value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
    64                                 </td>
    65                             </tr>
    66                        
    67                             <tr class="prop">
    68                                 <td valign="top" class="name">
    69                                     <label for="durationMinute">Duration Minute:</label>
    70                                 </td>
    71                                 <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}">
    72                                     <input type="text" id="durationMinute" name="durationMinute" value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
    73                                 </td>
    74                             </tr>
     62
     63                                <td valign="top" class="value">
     64                                    <input class="duration ${hasErrors(bean:entryInstance,field:'durationHour','errors')}"
     65                                        type="text" id="durationHour" name="durationHour"
     66                                        value="${fieldValue(bean:entryInstance,field:'durationHour')}" />
     67                                    :
     68                                    <input class="duration ${hasErrors(bean:entryInstance,field:'durationMinute','errors')}"
     69                                        type="text" id="durationMinute" name="durationMinute"
     70                                        value="${fieldValue(bean:entryInstance,field:'durationMinute')}" />
     71                                    <g:helpBalloon code="entry.duration" />
     72                                </td>
     73                            </tr>
    7574                       
    7675                            <tr class="prop">
     
    7877                                    <label for="dateEntered">Date Entered:</label>
    7978                                </td>
    80                                 <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'dateEntered','errors')}">
    81                                     <g:datePicker name="dateEntered" value="${entryInstance?.dateEntered}" ></g:datePicker>
     79                                <td valign="top" class="value">
     80                                    <g:formatDate date="${entryInstance?.dateEntered}" format="EEE, dd MMM yyyy @ HH:mm"/>
    8281                                </td>
    8382                            </tr>
     
    8786                                    <label for="enteredBy">Entered By:</label>
    8887                                </td>
    89                                 <td valign="top" class="value ${hasErrors(bean:entryInstance,field:'enteredBy','errors')}">
    90                                     <g:select optionKey="id" from="${Person.list()}" name="enteredBy.id" value="${entryInstance?.enteredBy?.id}" ></g:select>
     88                                <td valign="top" class="value">
     89                                    ${entryInstance?.enteredBy?.toString()}
    9190                                </td>
    9291                            </tr>
  • trunk/src/grails-app/views/entryDetailed/list.gsp

    r92 r98  
    3030                                <g:sortableColumn property="dateDone" title="Date Done" />
    3131                       
    32                                 <g:sortableColumn property="durationHour" title="Duration Hour" />
    33                        
    34                                 <g:sortableColumn property="durationMinute" title="Duration Minute" />
    35                        
     32                                <g:sortableColumn property="enteredBy" title="Entered By" />
     33
     34                            <th>Edit</th>
     35
     36                            <th>Show</th>
     37
    3638                        </tr>
    3739                    </thead>
     
    4042                        <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
    4143                       
    42                             <td><g:link action="show" id="${entryInstance.id}">${fieldValue(bean:entryInstance, field:'id')}</g:link></td>
     44                            <td>${fieldValue(bean:entryInstance, field:'id')}</td>
    4345                       
    4446                            <td>${fieldValue(bean:entryInstance, field:'task')}</td>
     
    4850                            <td>${fieldValue(bean:entryInstance, field:'dateDone')}</td>
    4951                       
    50                             <td>${fieldValue(bean:entryInstance, field:'durationHour')}</td>
    51                        
    52                             <td>${fieldValue(bean:entryInstance, field:'durationMinute')}</td>
     52                            <td>${fieldValue(bean:entryInstance, field:'enteredBy')}</td>
     53
     54                            <td><g:link action="edit" id="${entryInstance.id}">Edit</g:link></td>
     55
     56                            <td><g:link action="show" id="${entryInstance.id}">Show</g:link></td>
    5357                       
    5458                        </tr>
  • trunk/src/grails-app/views/entryDetailed/show.gsp

    r92 r98  
    3333                            <td valign="top" class="name">Task:</td>
    3434                           
    35                             <td valign="top" class="value"><g:link controller="task" action="show" id="${entryInstance?.task?.id}">${entryInstance?.task?.encodeAsHTML()}</g:link></td>
     35                            <td valign="top" class="value"><g:link controller="taskDetailed" action="show" id="${entryInstance?.task?.id}">${entryInstance?.task?.encodeAsHTML()}</g:link></td>
    3636                           
    3737                        </tr>
     
    7575                            <td valign="top" class="name">Entered By:</td>
    7676                           
    77                             <td valign="top" class="value"><g:link controller="person" action="show" id="${entryInstance?.enteredBy?.id}">${entryInstance?.enteredBy?.encodeAsHTML()}</g:link></td>
     77                            <td valign="top" class="value">${entryInstance?.enteredBy?.encodeAsHTML()}</td>
    7878                           
    7979                        </tr>
     
    8282                            <td valign="top" class="name">Entry Type:</td>
    8383                           
    84                             <td valign="top" class="value"><g:link controller="entryType" action="show" id="${entryInstance?.entryType?.id}">${entryInstance?.entryType?.encodeAsHTML()}</g:link></td>
     84                            <td valign="top" class="value">${entryInstance?.entryType?.encodeAsHTML()}</td>
    8585                           
    8686                        </tr>
  • trunk/src/grails-app/views/layouts/main.gsp

    r80 r98  
    55        <link rel="shortcut icon" href="${createLinkTo(dir:'images',file:'gnuMimsIcon.ico')}" type="image/x-icon" />
    66        <g:layoutHead />
     7        <g:helpBalloons/>
    78        <g:javascript library="application" />
    89    </head>
     
    1011    <!-- Added g:pageProperty so that onload in each page works -->
    1112    <body onload="<g:pageProperty name='body.onload'/>">
    12     <div id="wrapper" style="height: 100%;">
    13     <div id="top">
    14     </div>
    15     <div id="content" align="center">
    16         <div id="spinner" class="spinner" style="display:none;">
    17             <img src="${createLinkTo(dir:'images',file:'spinner.gif')}" alt="Spinner" />
    18         </div> 
    19         <!-- <div class="logo" style="text-align: center; width: 980px; height: 220px">
    20           <img src="${createLinkTo(dir:'images',file:'logo.png')}"
    21         alt="gnuMims" />
    22         <g:render template="/adminmenubar" />
    23 
    24         </div> -->
    25         <div id="Header">
    26             <a href="http://www.gnumims.org" id=HeaderLink></a>
     13        <div id="wrapper" style="height: 100%;">
     14            <div id="top">
     15            </div>
     16            <div id="content" align="center">
     17                <div id="spinner" class="spinner" style="display:none;">
     18                    <img src="${createLinkTo(dir:'images',file:'spinner.gif')}" alt="Spinner" />
     19                </div> 
     20                <!-- <div class="logo" style="text-align: center; width: 980px; height: 220px">
     21                <img src="${createLinkTo(dir:'images',file:'logo.png')}"
     22                alt="gnuMims" />
     23                <g:render template="/adminmenubar" />
     24       
     25                </div> -->
     26                <div id="Header">
     27                    <a href="http://www.gnumims.org" id=HeaderLink></a>
     28                </div>
     29                <div class="appControl">
     30                    <g:render template="/adminmenubar" />
     31                </div>
     32                <!-- Body wrapper div for IE -->
     33                <div style="text-align: center; width: 980px">
     34                    <g:layoutBody />
     35                </div><!--IE wrapper-->
     36            </div><!--content-->
     37            <div id="bottom">
     38            </div>
    2739        </div>
    28         <div class="appControl">
    29              <g:render template="/adminmenubar" />
    30         </div>
    31         <!-- Body wrapper div for IE -->
    32         <div style="text-align: center; width: 980px">
    33             <g:layoutBody />
    34         </div>
    35     </div>
    36     <div id="bottom">
    37     </div>
    38     </div>
    3940    </body>     
    4041</html>
  • trunk/src/grails-app/views/taskDetailed/show.gsp

    r96 r98  
    163163                            <th style="color:Black">Comment</th>
    164164                            <th style="color:Black">Date Done</th>
     165                            <th style="color:Black">Duration</th>
    165166                            <th style="color:Black">Entered By</th>
     167                            <th style="color:Black">Edit</th>
     168
    166169<!--                            <g:sortableColumn property="comment" title="Comment" />
    167170                       
     
    177180                           
    178181                                <td width="65%">${entry.comment}</td>
    179                            
    180182                                <td><g:formatDate date="${entry.dateDone}" format="EEE, dd MMM yyyy"/></td>
    181                        
     183                                <td>${entry.durationHour}:${entry.durationMinute}</td>
    182184                                <td>${entry.enteredBy}</td>
     185                                <td><g:link controller="entryDetailed" action="edit" id="${entry.id}">Edit</g:link></td>
     186
    183187                        </g:if>
    184188                       
     
    196200                            <th style="color:Black">Comment</th>
    197201                            <th style="color:Black">Date Done</th>
     202                            <th style="color:Black">Duration</th>
    198203                            <th style="color:Black">Entered By</th>
     204                            <th style="color:Black">Edit</th>
    199205<!--                            <g:sortableColumn property="commentW" title="Comment" />
    200206                       
     
    210216                           
    211217                                <td width="65%">${entry.comment}</td>
    212                            
    213218                                <td><g:formatDate date="${entry.dateDone}" format="EEE, dd MMM yyyy"/></td>
    214                        
     219                                <td>${entry.durationHour}:${entry.durationMinute}</td>
    215220                                <td>${entry.enteredBy}</td>
     221                                <td><g:link controller="entryDetailed" action="edit" id="${entry.id}">Edit</g:link></td>
    216222                        </g:if>
    217223                       
     
    225231
    226232            <div class="buttons">
    227                 <span class="menuButton" style="height:50px">
    228                     <g:link controller="entryDetailed" params="['task.id':taskInstance.id]" action="create">Add Entry</g:link>
    229                 </span>
     233                <g:form controller="entryDetailed">
     234                    <input type="hidden" name="taskInstance.id" value="${taskInstance?.id}" />
     235                    <span class="button">
     236                        <g:actionSubmit value="Add Entry" action="create"  class="edit"/>
     237                    </span>
     238                </g:form>
    230239            </div>
    231240
  • trunk/src/web-app/css/main.css

    r84 r98  
    1818    background: #fff;
    1919    color: #333;
    20     font: 11px verdana, arial, helvetica, sans-serif;
     20    font: 14px verdana, arial, helvetica, sans-serif;
    2121    background: transparent url("../images/brushed_metal.png") repeat fixed center;
    2222}
     
    6060    color: #006dba;
    6161    font-weight: normal;
    62     font-size: 16px;
     62    font-size: 17px;
    6363    margin: 0 0 .3em 0;
    6464}
     
    7171    background-color: #fcfcfc;
    7272    border: 1px solid #ccc;
    73     font: 11px verdana, arial, helvetica, sans-serif;
     73    font: 14px verdana, arial, helvetica, sans-serif;
    7474    margin: 2px 0;
    7575    padding: 2px 4px;
     
    7979}
    8080textarea {
    81         width: 250px;
     81        width: 450px;
    8282        height: 150px;
    8383        vertical-align: top;
     
    102102
    103103.appcontrolButton {
    104     font-size: 10px;
     104    font-size: 14px;
    105105    padding: 5px 5px;
    106106}
     
    127127
    128128.menuButton {
    129     font-size: 10px;
     129    font-size: 14px;
    130130    padding: 0 5px;
    131131}
     
    183183    border: 1px solid red;
    184184}
     185td.errors textarea {
     186    border: 1px solid red;
     187}
     188
     189input.duration {
     190    width:40px;
     191}
     192input.duration.errors {
     193    border: 1px solid red;
     194}
    185195
    186196/* TABLES */
     
    194204}
    195205td, th {
    196     font: 11px verdana, arial, helvetica, sans-serif;
    197     line-height: 12px;
     206    font: 14px verdana, arial, helvetica, sans-serif;
     207    line-height: 17px;
    198208    padding: 5px 6px;
    199209    text-align: left;
     
    203213    background: #fff url(../images/skin/shadow.jpg);
    204214    color: #666;
    205     font-size: 11px;
     215    font-size: 14px;
    206216    font-weight: bold;
    207217    line-height: 17px;
     
    211221    color: #333;
    212222    display: block;
    213     font-size: 10px;
     223    font-size: 14px;
    214224    text-decoration: none;
    215225    width: 100%;
     
    252262    border-top: 0;
    253263    color: #666;
    254     font-size: 10px;
     264    font-size: 14px;
    255265    overflow: hidden;
    256266    padding: 10px 3px;
     
    293303    border: 1px solid #ccc;
    294304    color: #666;
    295     font-size: 10px;
     305    font-size: 14px;
    296306    margin-top: -1px;
    297307    margin-bottom: 5px;
     
    305315    color: #333;
    306316    cursor: pointer;
    307     font-size: 10px;
     317    font-size: 14px;
    308318    font-weight: bold;
    309319    margin-left: 3px;
Note: See TracChangeset for help on using the changeset viewer.