/*
** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
*/
cson_value * json_artifact_ticket( cson_object * zParent, int rid ){
  cson_object * pay = NULL;
  Manifest *pTktChng = NULL;
  static cson_value * eventTypeLabel = NULL;
  if(! g.perm.RdTkt ){
    g.json.resultCode = FSL_JSON_E_DENIED;
    return NULL;
  }
  if(!eventTypeLabel){
    eventTypeLabel = json_new_string("ticket");
    json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel);
  }

  pTktChng = manifest_get(rid, CFTYPE_TICKET);
  if( pTktChng==0 ){
    g.json.resultCode = FSL_JSON_E_MANIFEST_READ_FAILED;
    return NULL;
  }
  pay = cson_new_object();
  cson_object_set(pay, "eventType", eventTypeLabel );
  cson_object_set(pay, "uuid", json_new_string(pTktChng->zTicketUuid));
  cson_object_set(pay, "user", json_new_string(pTktChng->zUser));
  cson_object_set(pay, "timestamp", json_julian_to_timestamp(pTktChng->rDate));
  manifest_destroy(pTktChng);
  return cson_object_value(pay);
}
Example #2
0
/*
** Implementation of the /json/diff page.
**
** Arguments:
**
** v1=1st version to diff
** v2=2nd version to diff
**
** Can come from GET, POST.payload, CLI -v1/-v2 or as positional
** parameters following the command name (in HTTP and CLI modes).
**
*/
cson_value * json_page_diff(){
  cson_object * pay = NULL;
  cson_value * v = NULL;
  char const * zFrom;
  char const * zTo;
  int nContext = 0;
  char doSBS;
  char doHtml;
  if(!g.perm.Read){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
  zFrom = json_find_option_cstr("v1",NULL,NULL);
  if(!zFrom){
    zFrom = json_command_arg(2);
  }
  if(!zFrom){
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Required 'v1' parameter is missing.");
    return NULL;
  }
  zTo = json_find_option_cstr("v2",NULL,NULL);
  if(!zTo){
    zTo = json_command_arg(3);
  }
  if(!zTo){
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Required 'v2' parameter is missing.");
    return NULL;
  }
  nContext = json_find_option_int("context",NULL,"c",5);
  doSBS = json_find_option_bool("sbs",NULL,"y",0);
  doHtml = json_find_option_bool("html",NULL,"h",0);
  v = json_generate_diff(zFrom, zTo, nContext, doSBS, doHtml);
  if(!v){
    if(!g.json.resultCode){
      json_set_err(FSL_JSON_E_UNKNOWN,
                   "Generating diff failed for unknown reason.");
    }
    return NULL;
  }
  pay = cson_new_object();
  cson_object_set(pay, "from", json_new_string(zFrom));
  cson_object_set(pay, "to", json_new_string(zTo));
  cson_object_set(pay, "diff", v);
  v = 0;
  
  return pay ? cson_object_value(pay) : NULL;
}
Example #3
0
/*
** Impl of /json/user/save.
*/
static cson_value * json_user_save(){
  /* try to get user info from GET/CLI args and construct
     a JSON form of it... */
  cson_object * u = cson_new_object();
  char const * str = NULL;
  char b = -1;
  int i = -1;
  int uid = -1;
  cson_value * payload = NULL;
  /* String properties... */
#define PROP(LK,SK) str = json_find_option_cstr(LK,NULL,SK);     \
  if(str){ cson_object_set(u, LK, json_new_string(str)); } (void)0
  PROP("name","n");
  PROP("password","p");
  PROP("info","i");
  PROP("capabilities","c");
#undef PROP
  /* Boolean properties... */
#define PROP(LK,DFLT) b = json_find_option_bool(LK,NULL,NULL,DFLT);     \
  if(DFLT!=b){ cson_object_set(u, LK, cson_value_new_bool(b)); } (void)0
  PROP("forceLogout",-1);
#undef PROP

#define PROP(LK,DFLT) i = json_find_option_int(LK,NULL,NULL,DFLT);   \
  if(DFLT != i){ cson_object_set(u, LK, cson_value_new_integer(i)); } (void)0
  PROP("uid",-99);
#undef PROP
  if( g.json.reqPayload.o ){
    cson_object_merge( u, g.json.reqPayload.o, CSON_MERGE_NO_RECURSE );
  }
  json_user_update_from_json( u );
  if(!g.json.resultCode){
    uid = cson_value_get_integer( cson_object_get(u, "uid") );
    assert((uid>0) && "Something went wrong in json_user_update_from_json()");
    payload = json_load_user_by_id(uid);
  }
  cson_free_object(u);
  return payload;
}
Example #4
0
/*
** Impl of /json/dir. 98% of it was taken directly
** from browse.c::page_dir()
*/
static cson_value * json_page_dir_list(){
  cson_object * zPayload = NULL; /* return value */
  cson_array * zEntries = NULL; /* accumulated list of entries. */
  cson_object * zEntry = NULL;  /* a single dir/file entry. */
  cson_array * keyStore = NULL; /* garbage collector for shared strings. */
  cson_string * zKeyName = NULL;
  cson_string * zKeySize = NULL;
  cson_string * zKeyIsDir = NULL;
  cson_string * zKeyUuid = NULL;
  cson_string * zKeyTime = NULL;
  cson_string * zKeyRaw = NULL;
  char * zD = NULL;
  char const * zDX = NULL;
  int nD;
  char * zUuid = NULL;
  char const * zCI = NULL;
  Manifest * pM = NULL;
  Stmt q = empty_Stmt;
  int rid = 0;
  if( !g.perm.Read ){
    json_set_err(FSL_JSON_E_DENIED, "Requires 'o' permissions.");
    return NULL;
  }
  zCI = json_find_option_cstr("checkin",NULL,"ci" );

  /* If a specific check-in is requested, fetch and parse it.  If the
  ** specific check-in does not exist, clear zCI.  zCI==0 will cause all
  ** files from all check-ins to be displayed.
  */
  if( zCI && *zCI ){
    pM = manifest_get_by_name(zCI, &rid);
    if( pM ){
      zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
    }else{
      json_set_err(FSL_JSON_E_UNRESOLVED_UUID,
                   "Checkin name [%s] is unresolved.",
                   zCI);
      return NULL;
    }
  }

  /* Jump through some hoops to find the directory name... */
  zDX = json_find_option_cstr("name",NULL,NULL);
  if(!zDX && !g.isHTTP){
    zDX = json_command_arg(g.json.dispatchDepth+1);
  }
  if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){
    zDX = NULL;
  }
  zD = zDX ? fossil_strdup(zDX) : NULL;
  nD = zD ? strlen(zD)+1 : 0;
  while( nD>1 && zD[nD-2]=='/' ){ zD[(--nD)-1] = 0; }

  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);

  /* Compute the temporary table "localfiles" containing the names
  ** of all files and subdirectories in the zD[] directory.
  **
  ** Subdirectory names begin with "/".  This causes them to sort
  ** first and it also gives us an easy way to distinguish files
  ** from directories in the loop that follows.
  */

  if( zCI ){
    Stmt ins;
    ManifestFile *pFile;
    ManifestFile *pPrev = 0;
    int nPrev = 0;
    int c;

    db_multi_exec(
                  "CREATE TEMP TABLE json_dir_files("
                  "  n UNIQUE NOT NULL," /* file name */
                  "  fn UNIQUE NOT NULL," /* full file name */
                  "  u DEFAULT NULL," /* file uuid */
                  "  sz DEFAULT -1," /* file size */
                  "  mtime DEFAULT NULL" /* file mtime in unix epoch format */
                  ");"
                  );

    db_prepare(&ins,
               "INSERT OR IGNORE INTO json_dir_files (n,fn,u,sz,mtime) "
               "SELECT"
               "  pathelement(:path,0),"
               "  CASE WHEN %Q IS NULL THEN '' ELSE %Q||'/' END ||:abspath,"
               "  a.uuid,"
               "  a.size,"
               "  CAST(strftime('%%s',e.mtime) AS INTEGER) "
               "FROM"
               "  mlink m, "
               "  event e,"
               "  blob a,"
               "  blob b "
               "WHERE"
               " e.objid=m.mid"
               " AND a.rid=m.fid"/*FILE artifact*/
               " AND b.rid=m.mid"/*CHECKIN artifact*/
               " AND a.uuid=:uuid",
               zD, zD
               );
    manifest_file_rewind(pM);
    while( (pFile = manifest_file_next(pM,0))!=0 ){
      if( nD>0
        && ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1)))
      ){
        continue;
      }
      /*printf("zD=%s, nD=%d, pFile->zName=%s\n", zD, nD, pFile->zName);*/
      if( pPrev
       && memcmp(&pFile->zName[nD],&pPrev->zName[nD],nPrev)==0
       && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/')
      ){
        continue;
      }
      db_bind_text( &ins, ":path", &pFile->zName[nD] );
      db_bind_text( &ins, ":abspath", &pFile->zName[nD] );
      db_bind_text( &ins, ":uuid", pFile->zUuid );
      db_step(&ins);
      db_reset(&ins);
      pPrev = pFile;
      for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){}
      if( c=='/' ) nPrev++;
    }
    db_finalize(&ins);
  }else if( zD && *zD ){
    db_multi_exec(
      "CREATE TEMP VIEW json_dir_files AS"
      " SELECT DISTINCT(pathelement(name,%d)) AS n,"
      " %Q||'/'||name AS fn,"
      " NULL AS u, NULL AS sz, NULL AS mtime"
      " FROM filename"
      "  WHERE name GLOB '%q/*'"
      " GROUP BY n",
      nD, zD, zD
    );
  }else{
    db_multi_exec(
      "CREATE TEMP VIEW json_dir_files"
      " AS SELECT DISTINCT(pathelement(name,0)) AS n, NULL AS fn"
      " FROM filename"
    );
  }

  if(zCI){
    db_prepare( &q, "SELECT"
                "  n as name,"
                "  fn as fullname,"
                "  u as uuid,"
                "  sz as size,"
                "  mtime as mtime "
                "FROM json_dir_files ORDER BY n");
  }else{/* UUIDs are all NULL. */
    db_prepare( &q, "SELECT n, fn FROM json_dir_files ORDER BY n");
  }

  zKeyName = cson_new_string("name",4);
  zKeyUuid = cson_new_string("uuid",4);
  zKeyIsDir = cson_new_string("isDir",5);
  keyStore = cson_new_array();
  cson_array_append( keyStore, cson_string_value(zKeyName) );
  cson_array_append( keyStore, cson_string_value(zKeyUuid) );
  cson_array_append( keyStore, cson_string_value(zKeyIsDir) );

  if( zCI ){
    zKeySize = cson_new_string("size",4);
    cson_array_append( keyStore, cson_string_value(zKeySize) );
    zKeyTime = cson_new_string("timestamp",9);
    cson_array_append( keyStore, cson_string_value(zKeyTime) );
    zKeyRaw = cson_new_string("downloadPath",12);
    cson_array_append( keyStore, cson_string_value(zKeyRaw) );
  }
  zPayload = cson_new_object();
  cson_object_set_s( zPayload, zKeyName,
                     json_new_string((zD&&*zD) ? zD : "/") );
  if( zUuid ){
    cson_object_set( zPayload, "checkin", json_new_string(zUuid) );
  }

  while( (SQLITE_ROW==db_step(&q)) ){
    cson_value * name = NULL;
    char const * n = db_column_text(&q,0);
    char const isDir = ('/'==*n);
    zEntry = cson_new_object();
    if(!zEntries){
      zEntries = cson_new_array();
      cson_object_set( zPayload, "entries", cson_array_value(zEntries) );
    }
    cson_array_append(zEntries, cson_object_value(zEntry) );
    if(isDir){
      name = json_new_string( n+1 );
      cson_object_set_s(zEntry, zKeyIsDir, cson_value_true() );
    } else{
      name = json_new_string( n );
    }
    cson_object_set_s(zEntry, zKeyName, name );
    if( zCI && !isDir){
      /* Don't add the uuid/size for dir entries - that data refers to
         one of the files in that directory :/. Entries with no
         --checkin may refer to N versions, and therefore we cannot
         associate a single size and uuid with them (and fetching all
         would be overkill for most use cases).
      */
      char const * fullName = db_column_text(&q,1);
      char const * u = db_column_text(&q,2);
      sqlite_int64 const sz = db_column_int64(&q,3);
      sqlite_int64 const ts = db_column_int64(&q,4);
      cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) );
      cson_object_set_s(zEntry, zKeySize,
                        cson_value_new_integer( (cson_int_t)sz ));
      cson_object_set_s(zEntry, zKeyTime,
          cson_value_new_integer( (cson_int_t)ts ));
      cson_object_set_s(zEntry, zKeyRaw,
                        json_new_string_f("/raw/%T?name=%t",
                                          fullName, u));
    }
  }
  db_finalize(&q);
  if(pM){
    manifest_destroy(pM);
  }
  cson_free_array( keyStore );

  free( zUuid );
  free( zD );
  return cson_object_value(zPayload);
}
/*
** Impl for /json/report/run
**
** Options/arguments:
**
** report=int (CLI: -report # or -r #) is the report number to run.
**
** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands.
**
** format=a|o Specifies result format: a=each row is an arry, o=each
** row is an object.  Default=o.
*/
static cson_value * json_report_run(){
  int nReport;
  Stmt q = empty_Stmt;
  cson_object * pay = NULL;
  cson_array * tktList = NULL;
  char const * zFmt;
  char * zTitle = NULL;
  Blob sql = empty_blob;
  int limit = 0;
  cson_value * colNames = NULL;
  int i;

  if(!g.perm.RdTkt){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'r' privileges.");
    return NULL;
  }
  nReport = json_report_get_number(3);
  if(nReport <=0){
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing or invalid 'number' (-n) parameter.");
    goto error;
  }
  zFmt = json_find_option_cstr2("format",NULL,"f",3);
  if(!zFmt) zFmt = "o";
  db_prepare(&q,
             "SELECT sqlcode, "
             " title"
             " FROM reportfmt"
             " WHERE rn=%d",
             nReport);
  if(SQLITE_ROW != db_step(&q)){
    json_set_err(FSL_JSON_E_INVALID_ARGS,
                 "Report number %d not found.",
                 nReport);
    db_finalize(&q);
    goto error;
  }

  limit = json_find_option_int("limit",NULL,"n",-1);

  
  /* Copy over report's SQL...*/
  blob_append(&sql, db_column_text(&q,0), -1);
  zTitle = mprintf("%s", db_column_text(&q,1));
  db_finalize(&q);
  db_prepare(&q, "%s", blob_str(&sql));

  /** Build the response... */
  pay = cson_new_object();

  cson_object_set(pay, "report", json_new_int(nReport));
  cson_object_set(pay, "title", json_new_string(zTitle));
  if(limit>0){
    cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit));
  }
  free(zTitle);
  zTitle = NULL;

  if(g.perm.TktFmt){
    cson_object_set(pay, "sqlcode",
                    cson_value_new_string(blob_str(&sql),
                                          (unsigned int)blob_size(&sql)));
  }
  blob_reset(&sql);

  colNames = cson_sqlite3_column_names(q.pStmt);
  cson_object_set( pay, "columnNames", colNames);
  for( i = 0 ; ((limit>0) ?(i < limit) : 1)
         && (SQLITE_ROW == db_step(&q));
       ++i){
    cson_value * row = ('a'==*zFmt)
      ? cson_sqlite3_row_to_array(q.pStmt)
      : cson_sqlite3_row_to_object2(q.pStmt,
                                    cson_value_get_array(colNames));
    ;
    if(row && !tktList){
      tktList = cson_new_array();
    }
    cson_array_append(tktList, row);
  }
  db_finalize(&q);
  cson_object_set(pay, "tickets",
                  tktList ? cson_array_value(tktList) : cson_value_null());

  goto end;

  error:
  assert(0 != g.json.resultCode);
  cson_value_free( cson_object_value(pay) );
  pay = NULL;
  end:

  return pay ? cson_object_value(pay) : NULL;

}
Example #6
0
/*
** Implementation of the /json/status page.
**
*/
cson_value * json_page_status(){
  Stmt q = empty_Stmt;
  cson_object * oPay;
  /*cson_object * files;*/
  int vid, nErr = 0;
  cson_object * tmpO;
  char * zTmp;
  i64 iMtime;
  cson_array * aFiles;

  if(!db_open_local(0)){
    json_set_err(FSL_JSON_E_DB_NEEDS_CHECKOUT, NULL);
    return NULL;
  }
  oPay = cson_new_object();
  cson_object_set(oPay, "repository",
                  json_new_string(db_repository_filename()));
  cson_object_set(oPay, "localRoot",
                  json_new_string(g.zLocalRoot));
  vid = db_lget_int("checkout", 0);
  if(!vid){
      json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
      return 0;
  }
  /* TODO: dupe show_common_info() state */
  tmpO = cson_new_object();
  cson_object_set(oPay, "checkout", cson_object_value(tmpO));

  zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
  cson_object_set(tmpO, "uuid", json_new_string(zTmp) );
  free(zTmp);

  cson_object_set( tmpO, "tags", json_tags_for_checkin_rid(vid, 0) );

  /* FIXME: optimize the datetime/timestamp queries into 1 query. */
  zTmp = db_text(0, "SELECT datetime(mtime) || "
                 "' UTC' FROM event WHERE objid=%d",
                 vid);
  cson_object_set(tmpO, "datetime", json_new_string(zTmp));
  free(zTmp);
  iMtime = db_int64(0, "SELECT CAST(strftime('%%s',mtime) AS INTEGER) "
                    "FROM event WHERE objid=%d", vid);
  cson_object_set(tmpO, "timestamp",
                  cson_value_new_integer((cson_int_t)iMtime));
#if 0
    /* TODO: add parent artifact info */
  tmpO = cson_new_object();
  cson_object_set( oPay, "parent", cson_object_value(tmpO) );
  cson_object_set( tmpO, "uuid", TODO );
  cson_object_set( tmpO, "timestamp", TODO );
#endif

  /* Now get the list of non-pristine files... */
  aFiles = cson_new_array();
  cson_object_set( oPay, "files", cson_array_value( aFiles ) );

  db_prepare(&q,
    "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
    "  FROM vfile "
    " WHERE is_selected(id)"
    "   AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zPathname = db_column_text(&q,0);
    int isDeleted = db_column_int(&q, 1);
    int isChnged = db_column_int(&q,2);
    int isNew = db_column_int(&q,3)==0;
    int isRenamed = db_column_int(&q,4);
    cson_object * oFile;
    char const * zStatus = "???";
    char * zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
    if( isDeleted ){
      zStatus = "deleted";
    }else if( isNew ){
      zStatus = "new" /* maintenance reminder: MUST come
                         BEFORE the isChnged checks. */;
    }else if( isRenamed ){
      zStatus = "renamed";
    }else if( !file_wd_isfile_or_link(zFullName) ){
      if( file_access(zFullName, F_OK)==0 ){
        zStatus = "notAFile";
        ++nErr;
      }else{
        zStatus = "missing";
        ++nErr;
      }
    }else if( 2==isChnged ){
      zStatus = "updatedByMerge";
    }else if( 3==isChnged ){
      zStatus = "addedByMerge";
    }else if( 4==isChnged ){
      zStatus = "updatedByIntegrate";
    }else if( 5==isChnged ){
      zStatus = "addedByIntegrate";
    }else if( 1==isChnged ){
      if( file_contains_merge_marker(zFullName) ){
        zStatus = "conflict";
      }else{
        zStatus = "edited";
      }
    }

    oFile = cson_new_object();
    cson_array_append( aFiles, cson_object_value(oFile) );
    /* optimization potential: move these keys into cson_strings
       to take advantage of refcounting. */
    cson_object_set( oFile, "name", json_new_string( zPathname ) );
    cson_object_set( oFile, "status", json_new_string( zStatus ) );

    free(zFullName);
  }
  cson_object_set( oPay, "errorCount", json_new_int( nErr ) );
  db_finalize(&q);

#if 0
  /* TODO: add "merged with" status.  First need (A) to decide on a
     structure and (B) to set up some tests for the multi-merge
     case.*/
  db_prepare(&q, "SELECT uuid, id FROM vmerge JOIN blob ON merge=rid"
                 " WHERE id<=0");
  while( db_step(&q)==SQLITE_ROW ){
    const char *zLabel = "MERGED_WITH";
    switch( db_column_int(&q, 1) ){
      case -1:  zLabel = "CHERRYPICK ";  break;
      case -2:  zLabel = "BACKOUT    ";  break;
      case -4:  zLabel = "INTEGRATE  ";  break;
    }
    blob_append(report, zPrefix, nPrefix);
    blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
  }
  db_finalize(&q);
  if( nErr ){
    fossil_fatal("aborting due to prior errors");
  }
#endif
  return cson_object_value( oPay );
}
/*
** Impl of /json/artifact. This basically just determines the type of
** an artifact and forwards the real work to another function.
*/
cson_value * json_page_artifact(){
  cson_object * pay = NULL;
  char const * zName = NULL;
  char const * zType = NULL;
  char const * zUuid = NULL;
  cson_value * entry = NULL;
  Blob uuid = empty_blob;
  int rc;
  int rid = 0;
  ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0];
  zName = json_find_option_cstr2("name", NULL, NULL, g.json.dispatchDepth+1);
  if(!zName || !*zName) {
    json_set_err(FSL_JSON_E_MISSING_ARGS,
                 "Missing 'name' argument.");
    return NULL;
  }

  if( validate16(zName, strlen(zName)) ){
    if( db_exists("SELECT 1 FROM ticket WHERE tkt_uuid GLOB '%q*'", zName) ){
      zType = "ticket";
      goto handle_entry;
    }
    if( db_exists("SELECT 1 FROM tag WHERE tagname GLOB 'event-%q*'", zName) ){
      zType = "tag";
      goto handle_entry;
    }
  }
  blob_set(&uuid,zName);
  rc = name_to_uuid(&uuid,-1,"*");
  /* FIXME: check for a filename if all else fails. */
  if(1==rc){
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
    goto error;
  }else if(2==rc){
    g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID;
    goto error;
  }
  zUuid = blob_str(&uuid);
  rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid);
  if(0==rid){
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
    goto error;
  }

  if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid)
      || db_exists("SELECT 1 FROM plink WHERE cid=%d", rid)
      || db_exists("SELECT 1 FROM plink WHERE pid=%d", rid)){
    zType = "checkin";
    goto handle_entry;
  }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                      " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){
    zType = "wiki";
    goto handle_entry;
  }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                      " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
    zType = "ticket";
    goto handle_entry;
  }else if ( db_exists("SELECT 1 FROM mlink WHERE fid = %d", rid) ){
    zType = "file";
    goto handle_entry;
  }else{
    g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
    goto error;
  }

  error:
  assert( 0 != g.json.resultCode );
  goto veryend;

  handle_entry:
  pay = cson_new_object();
  assert( (NULL != zType) && "Internal dispatching error." );
  for( ; dispatcher->name; ++dispatcher ){
    if(0!=strcmp(dispatcher->name, zType)){
      continue;
    }else{
      entry = (*dispatcher->func)(pay, rid);
      break;
    }
  }
  if(!g.json.resultCode){
    assert( NULL != entry );
    assert( NULL != zType );
    cson_object_set( pay, "type", json_new_string(zType) );
    cson_object_set( pay, "uuid", json_new_string(zUuid) );
    /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/
    /*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/
    if(cson_value_is_object(entry) && (cson_value_get_object(entry) != pay)){
      cson_object_set(pay, "artifact", entry);
    }
  }
  veryend:
  blob_reset(&uuid);
  if(g.json.resultCode && pay){
    cson_free_object(pay);
    pay = NULL;
  }
  return cson_object_value(pay);
}
Example #8
0
static cson_value * json_timeline_branch(){
  cson_value * pay = NULL;
  Blob sql = empty_blob;
  Stmt q = empty_Stmt;
  int limit = 0;
  if(!g.perm.Read){
    json_set_err(FSL_JSON_E_DENIED,
                 "Requires 'o' permissions.");
    return NULL;
  }
  json_timeline_temp_table();
  blob_append(&sql,
              "SELECT"
              "  blob.rid AS rid,"
              "  uuid AS uuid,"
              "  CAST(strftime('%s',event.mtime) AS INTEGER) as timestamp,"
              "  coalesce(ecomment, comment) as comment,"
              "  coalesce(euser, user) as user,"
              "  blob.rid IN leaf as isLeaf,"
              "  bgcolor as bgColor"
              " FROM event JOIN blob"
              " WHERE blob.rid=event.objid",
              -1);

  blob_append_sql(&sql,
               " AND event.type='ci'"
               " AND blob.rid IN (SELECT rid FROM tagxref"
               "  WHERE tagtype>0 AND tagid=%d AND srcid!=0)"
               " ORDER BY event.mtime DESC",
               TAG_BRANCH);
  limit = json_timeline_limit(20);
  if(limit>0){
    blob_append_sql(&sql," LIMIT %d ",limit);
  }
  db_prepare(&q,"%s", blob_sql_text(&sql));
  blob_reset(&sql);
  pay = json_stmt_to_array_of_obj(&q, NULL);
  db_finalize(&q);
  assert(NULL != pay);
  if(pay){
    /* get the array-form tags of each record. */
    cson_string * tags = cson_new_string("tags",4);
    cson_string * isLeaf = cson_new_string("isLeaf",6);
    cson_array * ar = cson_value_get_array(pay);
    cson_object * outer = NULL;
    unsigned int i = 0;
    unsigned int len = cson_array_length_get(ar);
    cson_value_add_reference( cson_string_value(tags) );
    cson_value_add_reference( cson_string_value(isLeaf) );
    for( ; i < len; ++i ){
      cson_object * row = cson_value_get_object(cson_array_get(ar,i));
      int rid = cson_value_get_integer(cson_object_get(row,"rid"));
      assert( rid > 0 );
      cson_object_set_s(row, tags, json_tags_for_checkin_rid(rid,0));
      cson_object_set_s(row, isLeaf,
                        json_value_to_bool(cson_object_get(row,"isLeaf")));
      cson_object_set(row, "rid", NULL)
        /* remove rid - we don't really want it to be public */;
    }
    cson_value_free( cson_string_value(tags) );
    cson_value_free( cson_string_value(isLeaf) );

    /* now we wrap the payload in an outer shell, for consistency with
       other /json/timeline/xyz APIs...
    */
    outer = cson_new_object();
    if(limit>0){
      cson_object_set( outer, "limit", json_new_int(limit) );
    }
    cson_object_set( outer, "timeline", pay );
    pay = cson_object_value(outer);
  }
  return pay;
}