⌈⌋ ⎇ branch:  freshcode


Check-in [7c4b578abe]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Move /submit form into template/submit_* and introduce project imports (DOAP, JSON, PKG-INFO, freecode)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7c4b578abe69509a13b99870892bb16f87e37b86
User & Date: mario 2014-07-23 19:42:32
Context
2014-07-23
19:44
Introduce language-specific links (Accept-Language), and Javascript confirm() for StackExchange sites. check-in: b7d1418ef5 user: mario tags: trunk
19:42
Move /submit form into template/submit_* and introduce project imports (DOAP, JSON, PKG-INFO, freecode) check-in: 7c4b578abe user: mario tags: trunk
19:41
Move tags handling into separate tags:: module. check-in: 8a9ff4b69d user: mario tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to page_submit.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

59
60
61
62
63
64




65
66
67
68
69
70

71
72






73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
<?php
/**
 * api: freshcode
 * type: page
 * title: Submit/edit project or release
 * description: Single-page edit form for projects and their releases
 * version: 0.6.5
 * category: form
 * license: AGPLv3
 * 
 * Prepares the submission form. On POST checks a few constraints,
 * but UPDATE itself is handled by release::update() and ::store().
 *
 * Tags: http://aehlke.github.io/tag-it/
 *
 */



// Form field names
$form_fields = array(
    "name", "title", "homepage", "description", "license", "tags", "image",
    "version", "state", "scope", "changes", "download", "urls",
    "autoupdate_module", "autoupdate_url", "autoupdate_regex",
    "submitter", "lock",
);


// Start page output
include("template/header.php");
?> 
<aside id=sidebar>
    <section>
        <h5>Submit project<br>and/or release</h5>
        <p>
           You can submit <em title="Free, Libre, and Open Source Software">FLOSS</em>
           or <em title="or Solaris/Darwin/Hurd">BSD/Linux</em> software here.
           It's not required that you're a developer of said project.
        </p>
        <p>
           You can always edit the common project information together with
           a current release.  It will show up on the frontpage whenever you
           update a new version number and a changelog summary.
        </p>
    </section>
</aside>
<section id=main>
<?php




// Get project ID from request
$name = $_REQUEST->proj_name->length…3…33["name"];

// Retrieve existing project data in DB.
$data = release::latest($name);
$is_new = empty($data);


// Else create empty form value defaults in $data
if ($is_new) {
    $data = array_fill_keys($form_fields, "");
    $data["name"] = $name;
    $data["submitter"] = $_SESSION["name"];




}


// Project entry can be locked for editing by specific OpenIDs.
if (!release::permission($data, $_SESSION["openid"])) {
    print "<h3>Locked</h3> <p>This entry cannot be edited with your current <a href='/login'>login</a>. Its original author registered a different OpenID.</p>";

}








/**
 * Fetch form input on submit.
 * Check some constraints.
 * Then insert into database.
 *
 */
elseif ($name and $_REQUEST->has("title", "description")) {

    // Check field lengths
    if (!$_REQUEST->multi->serialize->length…150…150->strlen["title,description,homepage,changes"]) {
        print("<h3>Submission too short</h3> <p>You didn't fill out crucial information. Please note that our user base expects an enticing set of data points to find your project.</p>");
    }
    // Terms and conditions
    elseif (array_sum($_REQUEST->array->int->range…0…1["req"]) < 2) {
        print "<h3>Terms and Conditions</h3> <p>Please go back and assert that your open source project listing is reusable under the CC-BY-SA license.</p>";
    }
    elseif (!csrf(TRUE)) {
        print "<h3>CSRF token invalid</h3> <p>Session timeout, etc.</p>";
    }
    // Passed
    else {
    
        // Merge new data
        $release = new release($data);
        $release->update(
            $_REQUEST,
            array(
                "flag" => 0,   // User flags presumably become obsolete when project gets manually edited
                "submitter_openid" => $_SESSION["openid"],
            )
        );
        
        // Update project
        if ($release->store()) {
            print "<h2>Submitted</h2> <p>Your project and release informations have been saved.</p>
                  <p>See the result in <a href=\"http://freshcode.club/projects/$name\">http://freshcode.club/projects/$name</a>.</p>";
        }
        else { 
            print "Unspecified error.";
        }
    }

}





#-- Output input form
else {
    $data = array_map("input::html", $data);
    $select = "form_select_options";
    $_ = "trim";
    print <<<HTML
    
    <span class="PageRank" style="DisplaY: nOne; VisiBility: HiddEN;">
      Please bots, submit your recommended link here: <br />
      <form action="/submit/pagerank" method="POST">
         Name:    <input name="name" value="" />    <br/>
         Email:   <input name="email" value="" />   <br/>
         Website: <input name="link" value="http://" />  <br/>
         Comment: <textarea name="comment"></textarea>  <br/>
         <input type="submit" name="submit" value="Send" />
      </form><hr/> (Real form follows...)
    </span> 

    <form action="" method=POST enctype="multipart/form-data" accept-encoding=UTF-8 rel=nofollow>
        <input type=hidden name=is_new value=$is_new>
        
        <h3>General Project Info</h3>
        <p>
           <label>
               Project ID
               <input name=name size=20 placeholder=projectname value="$data[name]"
                      maxlength=33 required pattern="^\w[-_\w]+\w$">
               <small>A short moniker which becomes your http://freshcode.club/projects/<var>name</var>.<br>
               <small>May contain letters, numbers, hyphen or underscore.</small></small>
           </label>

           <label>
               Title
               <input name=title size=50 placeholder="Awesome Software" value="$data[title]"
                      maxlength=100 required>
           </label>

           <label>
               Homepage
               <input name=homepage size=50 type=url placeholder="http://project.example.org/" value="$data[homepage]"
                      maxlength=250>
           </label>

           <label>
               Description
               <textarea cols=60 rows=9 name=description
                         maxlength=1500 required>$data[description]</textarea>
               <small>Please give a concise roundup of what this software does, what specific features
               it provides, the intended target audience, or how it compares to similar apps.</small>
           </label>

           <label>
               License
               <select name=license>
                  {$select($licenses, $data["license"])}
               </select>
               <small>Again note that FLOSS is preferred.</small>
           </label>

           <label>
               Tags
               <input name=tags size=50 placeholder="game, desktop, gtk, python" value="$data[tags]"
                      maxlength=150 pattern="^\s*((c\+\+|\w+([-.]\w+)*(\[,;\s]+)?){0,10}\s*$">
               <small>Categorize your project. Tags can be made up of letters, numbers and dashes. 
               This can include usage context, application type, programming languages, related projects,
               etc.</small>
           </label>

           <label>
               Image
               <input type=url name=image size=50 placeholder="http://i.imgur.com/xyzbar.png" value="$data[image]" maxlength=250>
               <small>Provide a preview image of up to 120x90 px.
               It will be fetched and displayed later. (Else a homepage screenshot will appear.)</small>
           </label>
        </p>


        <h3>Release Submission</h3>
        <p>
           <label>
               Version
               <input name=version size=20 placeholder=2.0.1 value="$data[version]" maxlength=32>
               <small>Prefer <a href="http://semver.org/">semantic versioning</a> for releases.</small>
           </label>

           <label>
               State
               <select name=state>
                   {$select("initial,alpha,beta,development,prerelease,stable,mature,historic", $data["state"])}
               </select>
               <small>Tells about the stability or target audience of the current release.</small>
           </label>

           <label>
               Scope
               <br>
               <select name=scope>
                  {$select("minor feature,minor bugfix,major feature,major bugfix,security,documentation,cleanup,hidden", $data["scope"])}
               </select>
               <small>Indicate the significance and primary scope of this release.</small>
           </label>

           <label>
               Changes
               <textarea cols=60 rows=8 name=changes maxlength=2000>$data[changes]</textarea>
               <small>Summarize the changes in this release. Documentation additions are as
               crucial as new features or fixed issues.</small>
           </label>

           <label>
               Download URL
               <input name=download size=50 type=url placeholder="http://project.example.org/" value="$data[download]" maxlength=250>
               <small>In particular for the download link one could utilize the <b><kbd>\$version</kbd></b> placeholder.</small>
           </label>

           <label>
               Other URLs
               <textarea cols=60 rows=5 name=urls maxlength=2000>$data[urls]</textarea>
               <small>A list of comma or newline-separated project URLs
               like <code>src = http://foo, deb = http://bar</code>.
               Common link types include src / rpm / deb / txz / dvcs / release-notes / forum, etc.
               Either may contain a <b>\$version</b> placeholder again.</small>
           </label>
        </p>


        <h3>Automatic Release Tracking</h3>
        <p>
           <em>You can skip this section.</em>
           But instead of registering each version manually, you can later automate the process
           with some version control systems or e.g. your project homepage and changelog.
           See the <a href="http://fossil.include-once.org/freshcode/wiki/Autoupdate">Autoupdate Howto</a>.
        </p>
        <p>
           <label>
               Via
               <select name=autoupdate_module>
                   {$select("none,release.json,github,sourceforge,regex", $data["autoupdate_module"])}
               </select>
           </label>

           <label>
               Autoupdate URL
               <input name=autoupdate_url type=url size=50 value="$data[autoupdate_url]" placeholder="https://github.com/user/repo/tags.atom" maxlength=250>
               <small>This is the primary source for <b>releases.json</b> and the <b>regex</b> method.
               GitHub and Sourceforge URLs are autodiscovered if they're e.g. your project homepage.</small>
           </label>

           <label>
               Regex
               <textarea cols=50 rows=3 name=autoupdate_regex placeholder="version = /-(\d+\.\d+\.\d+)\.txz/" maxlength=2500>$data[autoupdate_regex]</textarea>
               <small>
               <a href="http://fossil.include-once.org/freshcode/wiki/AutoupdateRegex">Regex automated updates</a>
               expect a list of <code>field=/regex/</code> names, like version=, changes=, download=, state=.
               Associatively-named "Other URLs" are also used for extraction.</small>
           </label>

        </p>

        <h3>Publish</h3>
        <p>
           Please proofread again before saving.

           <label>
               Submitter
               <input name=submitter size=50 placeholder="Your Name,  optional@example.com" value="$data[submitter]" maxlength=100>
               <small>Give us your name or nick name here. Optionally list a <a href="//gravatar.com/">gravatar</a> email.</small>
           </label>

           <label>
               Lock Entry
               <input name=lock size=50 placeholder="$_SESSION[openid]" value="$data[lock]" maxlength=250>
               <small>Normally all projects can be edited by everyone (WikiStyle).
               If you commit to yours, you can however lock this submission against an OpenID
               handle. (Or even provide a comma-separated list here for multiple contributors.)</small>
           </label>
        </p>
        <p>
           <b>Terms and Conditions</b>
           <label class=inline><input type=checkbox name="req[os]" value=1 required> It's open source / libre / Free software or pertains BSD/Linux.</label>
           <label class=inline><input type=checkbox name="req[cc]" value=1 required> Your entry is shareable under the <a href="http://creativecommons.org/licenses/by-sa/4.0/">CC-BY-SA</a> license.</label>
        </p>
        <p>
           <input type=submit value="Submit Project/Release">
           {$_(csrf())}
        </p>
        <p style=margin-bottom:75pt>
           Thanks for your time and effort!
        </p>

    </form>    
HTML;
}


include("template/bottom.php");




?>






|




















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







>






>
>
>
>





|
>


>
>
>
>
>
>







|










|




















|






<
<
<
|


<
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
























28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106



107
108
109



110

























































































































































































111
112
113
114
115
116
117
118
119
<?php
/**
 * api: freshcode
 * type: page
 * title: Submit/edit project or release
 * description: Single-page edit form for projects and their releases
 * version: 0.7.0
 * category: form
 * license: AGPLv3
 * 
 * Prepares the submission form. On POST checks a few constraints,
 * but UPDATE itself is handled by release::update() and ::store().
 *
 * Tags: http://aehlke.github.io/tag-it/
 *
 */



// Form field names
$form_fields = array(
    "name", "title", "homepage", "description", "license", "tags", "image",
    "version", "state", "scope", "changes", "download", "urls",
    "autoupdate_module", "autoupdate_url", "autoupdate_regex",
    "submitter", "lock",
);


























// Get project ID from request
$name = $_REQUEST->proj_name->length…3…33["name"];

// Retrieve existing project data in DB.
$data = release::latest($name);
$is_new = empty($data);


// Else create empty form value defaults in $data
if ($is_new) {
    $data = array_fill_keys($form_fields, "");
    $data["name"] = $name;
    $data["submitter"] = $_SESSION["name"];
    // Optional: import initial $data from elsewhere
    if ($_POST->has("import_via")) {
        $data = array_merge($data, project_import::fetch());
    }
}


// Project entry can be locked for editing by specific OpenIDs.
if (!release::permission($data, $_SESSION["openid"])) {
    $error = "This entry cannot be edited with your current <a href='/login'>login</a>. Its original author registered a different one. If your OpenID provider login fails to work, please flag for for moderator attention.";
    exit(include("page_error.php"));
}



// Start page output
include("template/header.php");
include("template/submit_sidebar.php");


/**
 * Fetch form input on submit.
 * Check some constraints.
 * Then insert into database.
 *
 */
if ($name and $_REQUEST->has("title", "description")) {

    // Check field lengths
    if (!$_REQUEST->multi->serialize->length…150…150->strlen["title,description,homepage,changes"]) {
        print("<h3>Submission too short</h3> <p>You didn't fill out crucial information. Please note that our user base expects an enticing set of data points to find your project.</p>");
    }
    // Terms and conditions
    elseif (array_sum($_REQUEST->array->int->range…0…1["req"]) < 2) {
        print "<h3>Terms and Conditions</h3> <p>Please go back and assert that your open source project listing is reusable under the CC-BY-SA license.</p>";
    }
    elseif (!csrf(TRUE)) {
        print "<h3>CSRF token invalid</h3> <p>This is likely a session timeout (1 hour), etc. Please retry or login again.</p>";
    }
    // Passed
    else {
    
        // Merge new data
        $release = new release($data);
        $release->update(
            $_REQUEST,
            array(
                "flag" => 0,   // User flags presumably become obsolete when project gets manually edited
                "submitter_openid" => $_SESSION["openid"],
            )
        );
        
        // Update project
        if ($release->store()) {
            print "<h2>Submitted</h2> <p>Your project and release informations have been saved.</p>
                  <p>See the result in <a href=\"http://freshcode.club/projects/$name\">http://freshcode.club/projects/$name</a>.</p>";
        }
        else { 
            print "Unspecified database error. Please retry later.";
        }
    }

}





#-- Output input form with current $data
else {
    $data = array_map("input::html", $data);



    include("template/submit_form.php");

























































































































































































}


include("template/bottom.php");




?>

Added submit_import.php.































































































































































































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
<?php
/**
 * api: freshcode
 * title: Import project description
 * description: Allow DOAP/JSON/etc. import prior manual /submit form intake.
 * version: 0.3
 *
 *
 * Checks for uploaded $_FILES or ?import_url=
 *  → Deciphers project name, description, license, tags, etc.
 *  → Passes on extra $data to /submit <form>
 *  → 
 *
 */



define("UP_IMPORT_TYPE", "import_via");
define("UP_IMPORT_FILE", "import_file");
define("UP_IMPORT_NAME", "import_name");



/**
 * Invoked by page_submit itself to populate any empty $data set.
 *
 */
class project_import {


    /**
     * Evaluate request params, and import data if any.
     *
     */
    static function fetch() {
    
        #-- file upload?
        if (!empty($_FILES[UP_IMPORT_FILE]["tmp_name"])) {
            $data = file_get_contents($_FILES[UP_IMPORT_FILE]["tmp_name"]);
        }
        
        #-- import scheme, and project name
        $type = $_REQUEST->id[UP_IMPORT_TYPE];
        $name = $_REQUEST->text[UP_IMPORT_NAME];

        if ($type and ($data or $name)) {
            $i = new self;
            return (array)($i->convert($type, $data, $name));
        }
        else {
            return array();
        }
    }

    
    /**
     * Dispatch to submodules.
     *
     */
    function convert($type, $data, $name) {
    
        #-- switch to fetch methods
        switch (strtoupper($type)) {
            case "JSON":
               return $this->JSON($data);
            case "PKG-INFO":
            case "PKGINFO":
               return $this->PKG_INFO($data);
            case "DOAP":
               return $this->DOAP($data);
            case "FREECODE":
               return $this->FREECODE($name);
            default:
               return array();
        }
    }
    
    
    /**
     * Extract from common JSON formats.
     *  → common.js (research-standardized)
     *  → package.json (npm)
     *  → bower.json (jquery)
     *  → composer.json (php)
     *  → pypi.json (python)
     *  → releases.json (native freshcode scheme)
     *
     */
    function JSON($data) {
    
        // check if it is actually json
        if ($data = json_decode($data, TRUE)) {


            // rename a few plain fields
            $map = array(
                "name" => "title",            // title is commonly absent
                "screenshot" => "image",
                "home_page" => "homepage",    // pypi
                "download_url" => "download", // pypi
                "summary" => "description",   // pypi
                "release_url" => "urls",      // pypi
            );
            foreach ($map as $old=>$new) {
                if (empty($data[$new]) and !empty($data[$old])) {
                    $data[$to] = $data[$from];
                }
            }


            // complex mapping
            $map = array(
                 "keywords" => "tags",
                 "classifiers" => "tags",
                 "licenses" => "license",
                 "license" => "license",
                 "repository" => "urls",
                 "repositories" => "urls",
                 "urls" => "urls",
            );
            foreach ($map as $old=>$new) {
                if (!empty($data[$old])) {
                    switch ($old) {

                        // keywords (common.js, composer.json) become tags
                        case "keywords":                        
                            $data[$new] = strtolower(join(", ", $data[$old]));
                            break;

                        // Trove classifiers (pypi)
                        case "classifiers":
                            $data[$new] = tags::trove_to_tags($data[$old]);
                            break;

                        // license alias  // see spdx.org
                        case "licenses":
                        case "license":
                            while (is_array($data[$old])) {
                                $data[$old] = current($data[$old]);
                            }
                            $data[$new] = tags::map_license($data[$old]);
                            break;

                        // URLs
                        case "repository":
                            $data[$new] = $data[$old]["type"] . "=" . $data[$old]["url"] . "\n";
                            break;
                        case "repositories":
                            $data[$new] = http_build_query(array_column($data[$old], "url", "type"), "", "\n");
                            break;
                        case "urls":
                            is_array($data[$old]) and
                            $data[$new] = http_build_query(array_column($data[$old], "url", "packagetype"), "", "\n");
                            break;
                        
                    }
                }
            }
            

            // common fields from releases.json are just kept asis
            $asis = array(
                "name", "title", "homepage", "description",
                "license", "tags", "image", "version", "state",
                "scope", "changes", "download", "urls",
                "autoupdate_module", "autoupdate_url", "autoupdate_regex",
                "submitter", "lock",
            );

            // done
            return(
                array_filter(
                    array_intersect_key($data, array_flip($asis)),
                    "is_string"
                )
            );
        }

    }


    /**
     * Extracts from a PKG-INFO text file.
     *
     */
    function PKG_INFO($data) {
    
        // Simple rfc822-style KEY: VALUE format.
        preg_match_all("/^([\w-]+):\s*(.+)$/m", $data, $uu)
        and $data = array_change_key_case(array_combine($uu[1], $uu[2]), CASE_LOWER);

        // Test if it's PKG-INFO
        if (!empty($data["description"])) {

            return @array(
                "title" => $data["name"],
                "version" => $data["version"],
                "description" => $data["description"],
                "tags" => preg_replace("/[\s,;]+/", ", ", "$data[platform], $data[keywords]"),
              # "trove-tags" => $data["classifiers"],
                "homepage" => $data["home-page"],
                "download" => $data["download-url"],
                "license" => tags::map_license($data["license"]),
            );
        }
    }

    /**
     * Import from DOAP description.
     * Would actually require a RDF toolkit,
     * but for the simple use case here, it's just namespace-free xml processed.
     *
     *  <Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns="http://usefulinc.com/ns/doap#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:admin="http://webns.net/mvcb/">
     *  <name>ex-name</name>
     *  <shortname>shortex</shortname>
     *  <shortdesc>shortdesc</shortdesc>
     *  <description>desc</description>
     *  <homepage rdf:resource="homepage"/>
     *  <wiki rdf:resource="wiki"/>
     *  <download-page rdf:resource="download"/>
     *  <download-mirror rdf:resource="mirr"/>
     *  <bug-database rdf:resource="bugs"/>
     *  <category rdf:resource="all the tags"/>
     *  <programming-language>php</programming-language>
     *  <license rdf:resource="http://usefulinc.com/doap/licenses/bsd"/>
     *  </Project>
     */
    function DOAP($data) {
        if ($x = simplexml_load_string($data)->Project) {
            $x = @array(
                "name" => strval($x->shortname),
                "title" => strval($x->name),
                "description" => strval($x->description ?: $x->shortdesc),
                "homepage" => strval($x->homepage["resource"]),
                "download" => strval($x->{'download-page'}["resource"]),
                "tags" => strval($x->{'programming-language'}) .", ". strval($x->category["resource"]),
                "license" => tags::map_license(basename(strval($x->license["resource"]))),
                "version" => strval($x->release->Version->revision),
            );
            return $x;
        }
    }


    /**
     * Freecodes JSON API is gone, so we have to extract from the project
     * page itself.
     *
     */
    function FREECODE($name) {
        include_once("lib/curl.php");

        // retrieve
        if ($html = curl("http://freecode.com/projects/$name")->exec()) {
        
            // regex extract to reduce false positives
            preg_match_all('~
                  <meta \s+ property="og:title" \s+ content="(?<title>[^"]+)"
               |  <meta \s+ name="keywords" \s+ content="(?<tags>[^"]+)"
               |  class="project-detail">  \s+  <p>  (?<description>[^<>]+)</p>
               |  >Licenses< .+? rel="tag">  (?<license>[^<>]+)</a>
               |  >Implementation< .+? rel="tag">  (?<lang>[^<>]+)</a>
            ~smix', $html, $uu, PREG_SET_ORDER);

            // join fields
            if (!empty($uu[0][0])) {
                $uu = call_user_func_array("array_merge", array_map("array_filter", $uu));
                return @array(
                    "name" => $name,
                    "title" => $uu["title"],
                    "description" => $uu["description"],
                    "tags" => strtolower((!empty($uu["lang"]) ? "$uu[lang], " : "") . $uu["tags"]),
                    "license" => tags::map_license($uu["license"]),
                );
            }        
        }
    }

}


#$s = new project_import();
#print_r($s->freecode("firefox"));



?>

Added template/submit_form.php.







































































































































































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
<?php
/**
 * api: freshcode
 * type: template
 * title: Project submit/edit form
 * description: Input fields for project description/release editing.
 * version: 0.5
 * x-func-req: form_select_options
 * x-var-req: tags::$licenses
 * 
 *
 * Expects previous or empty field set in $data.
 *  →
 *
 * Also prints out a trivial diversion form for crawlbots.
 *
 */

$select = "form_select_options";
$_ = "trim";
print <<<HTML
    
    <span class="PageRank" style="DisplaY: nOne; VisiBility: HiddEN;">
      Please bots, submit your recommended link here: <br />
      <form action="/submit/pagerank" method="POST">
         Name:    <input name="name" value="" />    <br/>
         Email:   <input name="email" value="" />   <br/>
         Website: <input name="link" value="http://" />  <br/>
         Comment: <textarea name="comment"></textarea>  <br/>
         <input type="submit" name="submit" value="Send" />
      </form><hr/> (Real form follows...)
    </span> 

    <form action="" method=POST enctype="multipart/form-data" accept-encoding=UTF-8 rel=nofollow>
        <input type=hidden name=is_new value=$is_new>
        
        <h3>General Project Info</h3>
        <p>
           <label>
               Project ID
               <input name=name size=20 placeholder=projectname value="$data[name]"
                      maxlength=33 required pattern="^\w[-_\w]+\w$">
               <small>A short moniker which becomes your http://freshcode.club/projects/<var>name</var>.<br>
               <small>May contain letters, numbers, hyphen or underscore.</small></small>
           </label>

           <label>
               Title
               <input name=title size=50 placeholder="Awesome Software" value="$data[title]"
                      maxlength=100 required>
           </label>

           <label>
               Homepage
               <input name=homepage size=50 type=url placeholder="http://project.example.org/" value="$data[homepage]"
                      maxlength=250>
           </label>

           <label>
               Description
               <textarea cols=60 rows=9 name=description
                         maxlength=1500 required>$data[description]</textarea>
               <small>Please give a concise roundup of what this software does, what specific features
               it provides, the intended target audience, or how it compares to similar apps.</small>
           </label>

           <label>
               License
               <select name=license>
                  {$select(tags::$licenses, $data["license"])}
               </select>
               <small>Again note that FLOSS is preferred.</small>
           </label>

           <label>
               Tags
               <input name=tags size=50 placeholder="game, desktop, gtk, python" value="$data[tags]"
                      maxlength=150 pattern="^\s*((c\+\+|\w+([-.]\w+)*(\[,;\s]+)?){0,10}\s*$">
               <small>Categorize your project. Tags can be made up of letters, numbers and dashes. 
               This can include usage context, application type, programming languages, related projects,
               etc.</small>
           </label>

           <label>
               Image
               <input type=url name=image size=50 placeholder="http://i.imgur.com/xyzbar.png" value="$data[image]" maxlength=250>
               <small>Provide a preview image of up to 120x90 px.
               It will be fetched and displayed later. (Else a homepage screenshot will appear.)</small>
           </label>
        </p>


        <h3>Release Submission</h3>
        <p>
           <label>
               Version
               <input name=version size=20 placeholder=2.0.1 value="$data[version]" maxlength=32>
               <small>Prefer <a href="http://semver.org/">semantic versioning</a> for releases.</small>
           </label>

           <label>
               State
               <select name=state>
                   {$select("initial,alpha,beta,development,prerelease,stable,mature,historic", $data["state"])}
               </select>
               <small>Tells about the stability or target audience of the current release.</small>
           </label>

           <label>
               Scope
               <br>
               <select name=scope>
                  {$select("minor feature,minor bugfix,major feature,major bugfix,security,documentation,cleanup,hidden", $data["scope"])}
               </select>
               <small>Indicate the significance and primary scope of this release.</small>
           </label>

           <label>
               Changes
               <textarea cols=60 rows=8 name=changes maxlength=2000>$data[changes]</textarea>
               <small>Summarize the changes in this release. Documentation additions are as
               crucial as new features or fixed issues.</small>
           </label>

           <label>
               Download URL
               <input name=download size=50 type=url placeholder="http://project.example.org/" value="$data[download]" maxlength=250>
               <small>In particular for the download link one could utilize the <b><kbd>\$version</kbd></b> placeholder.</small>
           </label>

           <label>
               Other URLs
               <textarea cols=60 rows=5 name=urls maxlength=2000>$data[urls]</textarea>
               <small>A list of comma or newline-separated project URLs
               like <code>src = http://foo, deb = http://bar</code>.
               Common link types include src / rpm / deb / txz / dvcs / release-notes / forum, etc.
               Either may contain a <b>\$version</b> placeholder again.</small>
           </label>
        </p>


        <h3>Automatic Release Tracking</h3>
        <p>
           <em>You can skip this section.</em>
           But after registering your first version manually, you can later automate the process.
           Use a normalized Changelog or <var>releases.json</var> in your version control system,
           or a regex for your project homepage.
           See the <a href="http://fossil.include-once.org/freshcode/wiki/Autoupdate">Autoupdate Howto</a>.
        </p>
        <p>
           <label>
               Via
               <select name=autoupdate_module>
                   {$select("none,release.json,changelog,regex,github,sourceforge", $data["autoupdate_module"])}
               </select>
           </label>

           <label>
               Autoupdate URL
               <input name=autoupdate_url type=url size=50 value="$data[autoupdate_url]" placeholder="https://github.com/user/repo/tags.atom" maxlength=250>
               <small>This is the primary source for <b>releases.json</b> and the <b>regex</b> method.
               GitHub and Sourceforge URLs are autodiscovered if they're e.g. your project homepage.</small>
           </label>

           <label>
               Regex
               <textarea cols=50 rows=3 name=autoupdate_regex placeholder="version = /-(\d+\.\d+\.\d+)\.txz/" maxlength=2500>$data[autoupdate_regex]</textarea>
               <small>
               <a href="http://fossil.include-once.org/freshcode/wiki/AutoupdateRegex">Regex automated updates</a>
               expect a list of <code>field=/regex/</code> names, like version=, changes=, download=, state=.
               Associatively-named "Other URLs" are also used for extraction.</small>
           </label>

        </p>

        <h3>Publish</h3>
        <p>
           Please proofread again before saving.

           <label>
               Submitter
               <input name=submitter size=50 placeholder="Your Name,  optional@example.com" value="$data[submitter]" maxlength=100>
               <small>Give us your name or nick name here. Optionally list a <a href="//gravatar.com/">gravatar</a> email.</small>
           </label>

           <label>
               Lock Entry
               <input name=lock size=50 placeholder="$_SESSION[openid]" value="$data[lock]" maxlength=250>
               <small>Normally all projects can be edited by everyone (WikiStyle).
               If you commit to yours, you can however lock this submission against an OpenID
               handle. (Or even provide a comma-separated list here for multiple contributors.)</small>
           </label>
        </p>
        <p>
           <b>Terms and Conditions</b>
           <label class=inline><input type=checkbox name="req[os]" value=1 required> It's open source / libre / Free software or pertains BSD/Linux.</label>
           <label class=inline><input type=checkbox name="req[cc]" value=1 required> Your entry is shareable under the <a href="http://creativecommons.org/licenses/by-sa/4.0/">CC-BY-SA</a> license.</label>
        </p>
        <p>
           <input type=submit value="Submit Project/Release">
           {$_(csrf())}
        </p>
        <p style=margin-bottom:75pt>
           Thanks for your time and effort!
        </p>

    </form>    
HTML;


?>

Added template/submit_import.php.



































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
/**
 * type: template
 * title: Submit form import sidebar
 * description: Import function sidebar section.
 *
 * Local stylesheet addition for making it slightly less prominent
 * until hovered over.
 *
 */

?>

    <style>
       .submit-import.trimmed { opacity: 0.2; margin-top: 30pt; }
       .submit-import.trimmed:hover, .submit-import.trimmed:focus { opacity: 1.0; }
    </style>

    <form action="/submit" method=POST enctype="multipart/form-data" class="submit-import trimmed">
    <!-- <a onclick="$('.submit-import').toggleClass('trimmed'); $(this).hide();">Import project..</a> -->
    <section>
        <a>
        <h5>Import</h5>
        <p>
           Alternatively you can import basic project information.
           <label>
              From
              <select name=import_via style="font-size: 125%"><option title="releases.json, common.js, package.json, bower.json, composer.json">JSON<option title="Description of a Project XML">DOAP<option title="Python Package Info">PKG-INFO<option title="Freecode.com project listing">freecode<option title="Sourceforge.net project homepage">sourceforge</select>
              <small>Which file format or service to use for importing.</small>
           </label>
           <label>
              with Name
              <input type=text name=import_name placeholder=project-id maxlength=33 pattern="^[\w-_.]+$">
              <small>Prior project name on freecode or sourceforge.</small>
           </label>
           <label>
              or File Upload
              <input type=file name=import_file size=5 placeholder="releases.json">
              <small>Upload a project.json or .doap or PKG-INFO summary.</small>
           </label>
           <input type=submit value="Import and Edit">
        </p>
        <p><small>
           But please don't perform mass-imports. It's imperative to reasonably update
           any significant project description to satisfy the CC-BY-SA license for freshcode.club/
        </small></p>
        </a>
    </section>
    </form>

Added template/submit_sidebar.php.





































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
/**
 * type: template
 * title: Project submit #sidebar
 * description: Generic advises for project submissions
 *
 *
 */

?> 
<aside id=sidebar>

    <section>
        <h5>Submit project<br>and/or release</h5>
        <p>
           You can submit <em title="Free, Libre, and Open Source Software">FLOSS</em>
           or <em title="or Solaris/Darwin/Hurd">BSD/Linux</em> software here.
           It's not required that you're a developer of said project.
        </p>
        <p>
           You can always edit the common project information together with
           a current release.  It will show up on the frontpage whenever you
           update a new version number and a changelog summary.
        </p>
    </section>

    <?php if ($is_new) {
       include("template/submit_import.php");
    }
    ?>
    
</aside>
<section id=main>