Fossil

Artifact [f9052a7595]
Login

Artifact f9052a7595326d43332b1fbb0f8b74ebc338b8aa:


/*
** Copyright (c) 2010 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)

** This program is distributed in the hope that it will be useful,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
**
** This file contains code to do formatting of event messages:
**
**     Milestones
**     Blog posts
**     New articles
**     Process checkpoints
**     Announcements
*/
#include <assert.h>
#include <ctype.h>
#include "config.h"
#include "event.h"

/*
** WEBPAGE: event
** URL: /event?name=EVENTID
**
** Display an existing event identified by EVENTID
*/
void event_page(void){
  char *zTag;
  int rid = 0;
  const char *zEventId;
  char *zETime;
  Manifest m;
  Blob content;
  Blob fullbody;
  Blob title;
  Blob tail;


  /* wiki-read privilege is needed in order to read events.
  */
  login_check_credentials();
  if( !g.okRdWiki ){
    login_needed();
    return;
  }

  zEventId = PD("name","nil");
  zTag = mprintf("event-%s", zEventId);
  rid = db_int(0, 
    "SELECT rid FROM tagxref"
    " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
    " ORDER BY mtime DESC", zTag
  );
  free(zTag);
  if( rid==0 ){
    style_header("No Such Event");
    @ Unknown event: %h(zEventId)
    style_footer();
    return;
  }

  /* Extract the event content.
  */
  memset(&m, 0, sizeof(m));
  blob_zero(&m.content);
  content_get(rid, &content);
  manifest_parse(&m, &content);
  if( m.type!=CFTYPE_EVENT ){
    fossil_panic("Object #%d is not an event", rid);
  }
  zETime = db_text(0, "SELECT datetime(%.17g)", m.rEventDate);
  blob_init(&fullbody, m.zWiki, -1);
  if( wiki_find_title(&fullbody, &title, &tail) ){
    style_header(blob_str(&title));
  }else{
    style_header("Event %s", zEventId);
    tail = fullbody;
  }
  wiki_convert(&tail, 0, 0);
  style_footer();
}

/*
** WEBPAGE: eventedit
** URL: /eventedit?name=EVENTID
**
** Edit an event.  If name is omitted, create a new event.
*/
void eventedit_page(void){
  char *zTag;
  int rid = 0;
  Blob event;
  const char *zEventId;
  char *zHtmlPageName;
  int n;
  const char *z;
  char *zBody = (char*)P("w");
  char *zETime = (char*)P("t");
  const char *zComment = P("c");
  const char *zClr;

  if( zBody ){
    zBody = mprintf("%s", zBody);
  }
  login_check_credentials();
  zEventId = P("name");
  if( zEventId==0 ){
    zEventId = db_text(0, "SELECT lower(hex(randomblob(20)))");
  }else{
    int nEventId = strlen(zEventId);
    if( nEventId!=40 || !validate16(zEventId, 40) ){
      fossil_redirect_home();
      return;
    }
  }
  zTag = mprintf("event-%s", zEventId);
  rid = db_int(0, 
    "SELECT rid FROM tagxref"
    " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%Q)"
    " ORDER BY mtime DESC", zTag
  );
  free(zTag);

  /* Need both check-in and wiki-write or wiki-create privileges in order
  ** to edit/create an event.
  */
  if( !g.okWrite || (rid && !g.okWrWiki) || (!rid && !g.okNewWiki) ){
    login_needed();
    return;
  }

  /* Figure out the color */
  if( rid ){
    zClr = db_text("", "SELECT bgcolor  FROM event WHERE objid=%d", rid);
  }else{
    zClr = "";
  }
  zClr = PD("clr",zClr);
  if( strcmp(zClr,"##")==0 ) zClr = PD("cclr","");


  /* If editing an existing event, extract the key fields to use as
  ** a starting point for the edit.
  */
  if( rid && (zBody==0 || zETime==0 || zComment==0) ){
    Manifest m;
    Blob content;
    memset(&m, 0, sizeof(m));
    blob_zero(&m.content);
    content_get(rid, &content);
    manifest_parse(&m, &content);
    if( m.type==CFTYPE_EVENT ){
      if( zBody==0 ) zBody = m.zWiki;
      if( zETime==0 ){
        zETime = db_text(0, "SELECT datetime(%.17g)", m.rEventDate);
      }
      if( zComment==0 ) zComment = m.zComment;
    }
  }
  zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime);
  if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){
    char *zDate;
    Blob cksum;
    int nrid;
    blob_zero(&event);
    db_begin_transaction();
    login_verify_csrf_secret();
    blob_appendf(&event, "C %F\n", zComment);
    zDate = db_text(0, "SELECT datetime('now')");
    zDate[10] = 'T';
    blob_appendf(&event, "D %s\n", zDate);
    free(zDate);
    zETime[10] = 'T';
    blob_appendf(&event, "E %s %s\n", zETime, zEventId);
    zETime[10] = ' ';
    if( rid ){
      char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
      blob_appendf(&event, "P %s\n", zUuid);
      free(zUuid);
    }
    if( zClr && zClr[0] ){
      blob_appendf(&event, "T +bgcolor * %F\n", zClr);
    }
    if( g.zLogin ){
      blob_appendf(&event, "U %F\n", g.zLogin);
    }
    blob_appendf(&event, "W %d\n%s\n", strlen(zBody), zBody);
    md5sum_blob(&event, &cksum);
    blob_appendf(&event, "Z %b\n", &cksum);
    blob_reset(&cksum);
    nrid = content_put(&event, 0, 0);
    db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid);
    manifest_crosslink(nrid, &event);
    blob_reset(&event);
    content_deltify(rid, nrid, 0);
    db_end_transaction(0);
    cgi_redirectf("event?name=%T", zEventId);
  }
  if( P("cancel")!=0 ){
    cgi_redirectf("event?name=%T", zEventId);
    return;
  }
  if( zBody==0 ){
    zBody = mprintf("<i>Event Text</i>");
  }
  zHtmlPageName = mprintf("Edit Event %S", zEventId);
  style_header(zHtmlPageName);
  if( P("preview")!=0 ){
    Blob title, tail, com;
    @ <p><b>Timeline comment preview:</b></p>
    @ <blockquote>
    @ <table border="0">
    if( zClr && zClr[0] ){
      @ <tr><td style="background-color: %h(zClr);">
    }else{
      @ <tr><td>
    }
    blob_init(&com, zComment, -1);
    wiki_convert(&com, 0, WIKI_INLINE);
    @ </td></tr></table>
    @ </blockquote>
    @ <p><b>Page content preview:</b><p>
    @ <blockquote>
    blob_init(&event, zBody, -1);
    if( wiki_find_title(&event, &title, &tail) ){
      @ <h2 align="center">%h(blob_str(&title))</h2>
      wiki_convert(&tail, 0, 0);
    }else{
      wiki_convert(&event, 0, 0);
    }
    @ </blockquote><hr />
    blob_reset(&event);
  }
  for(n=2, z=zBody; z[0]; z++){
    if( z[0]=='\n' ) n++;
  }
  if( n<20 ) n = 20;
  if( n>40 ) n = 40;
  @ <form method="post" action="%s(g.zBaseURL)/eventedit"><div>
  login_insert_csrf_secret();
  @ <input type="hidden" name="name" value="%h(zEventId)" />
  @ <table border="0" cellspacing="10">

  @ <tr><td align="right" valign="top"><b>Event&nbsp;Time:</b></td>
  @ <td valign="top">
  @   <input type="text" name="t" size="25" value="%h(zETime)" /></p>
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Timeline&nbsp;Comment:</b></td>
  @ <td valign="top">
  @ <textarea name="c" class="eventedit" cols="80" 
  @  rows="3" wrap="virtual">%h(zComment)</textarea>
  @ </td></tr>

  @ <tr><td align="right" valign="top"><b>Background&nbsp;Color:</b></td>
  @ <td valign="top">
  render_color_chooser(0, zClr, 0, "clr", "cclr");
  @ </td></tr>
  
  @ <tr><td align="right" valign="top"><b>Page&nbsp;Content:</b></td>
  @ <td valign="top">
  @ <textarea name="w" class="eventedit" cols="80" 
  @  rows="%d(n)" wrap="virtual">%h(zBody)</textarea>
  @ </td></tr>

  @ <tr><td colspan="2">
  @ <input type="submit" name="preview" value="Preview Your Changes" />
  @ <input type="submit" name="submit" value="Apply These Changes" />
  @ <input type="submit" name="cancel" value="Cancel" />
  @ </td></tr></table>
  @ </div></form>
  style_footer();
}