From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:03 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:03 +0900 Subject: [Slashdotjp-dev 321] CVS update: slashjp/Slash/Client Message-ID: <20060712113103.12DBC2AC08C@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:03 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:03 +0900 Subject: [Slashdotjp-dev 322] CVS update: slashjp/Slash/XML/Atom Message-ID: <20060712113103.C913A2AC08C@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:02 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:02 +0900 Subject: [Slashdotjp-dev 322] CVS update: slashjp/tagboxes Message-ID: <20060712113102.4B94E2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:07 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:07 +0900 Subject: [Slashdotjp-dev 322] CVS update: slashjp/plugins/Ajax Message-ID: <20060712113107.9BF732AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:08 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:08 +0900 Subject: [Slashdotjp-dev 323] CVS update: slashjp/plugins/BlockProxyNet Message-ID: <20060712113108.5AC132AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:09 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:09 +0900 Subject: [Slashdotjp-dev 324] CVS update: slashjp/plugins/Bookmark Message-ID: <20060712113109.1C5962AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:09 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:09 +0900 Subject: [Slashdotjp-dev 325] CVS update: slashjp/plugins/Console Message-ID: <20060712113109.D61A62AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:10 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:10 +0900 Subject: [Slashdotjp-dev 326] CVS update: slashjp/plugins/Daypass Message-ID: <20060712113110.AD9542AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:11 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:11 +0900 Subject: [Slashdotjp-dev 327] CVS update: slashjp/plugins/OAI Message-ID: <20060712113111.6A87D2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:12 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:12 +0900 Subject: [Slashdotjp-dev 328] CVS update: slashjp/plugins/Remarks Message-ID: <20060712113112.29C362AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:13 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:13 +0900 Subject: [Slashdotjp-dev 329] CVS update: slashjp/plugins/ResKey Message-ID: <20060712113113.036122AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:13 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:13 +0900 Subject: [Slashdotjp-dev 330] CVS update: slashjp/plugins/ScheduleShifts Message-ID: <20060712113113.BE7DE2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:14 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:14 +0900 Subject: [Slashdotjp-dev 331] CVS update: slashjp/plugins/SearchToo Message-ID: <20060712113114.83E0D2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:15 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:15 +0900 Subject: [Slashdotjp-dev 330] CVS update: slashjp/plugins/Tags Message-ID: <20060712113115.58DBD2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:16 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:16 +0900 Subject: [Slashdotjp-dev 331] CVS update: slashjp/plugins/Unsubscribe Message-ID: <20060712113116.1C43A2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:31:16 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:31:16 +0900 Subject: [Slashdotjp-dev 332] CVS update: slashjp/plugins/Validator Message-ID: <20060712113116.E079E2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:35:54 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:35:54 +0900 Subject: [Slashdotjp-dev 333] CVS update: slashjp/Slash/Client/lib Message-ID: <20060712113554.A0FCE2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:35:55 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:35:55 +0900 Subject: [Slashdotjp-dev 334] CVS update: slashjp/Slash/Client/t Message-ID: <20060712113555.5E2432AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:02 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:02 +0900 Subject: [Slashdotjp-dev 335] CVS update: slashjp/plugins/Ajax/htdocs Message-ID: <20060712113602.C19592AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:05 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:05 +0900 Subject: [Slashdotjp-dev 336] CVS update: slashjp/plugins/Ajax/templates Message-ID: <20060712113605.9F9992AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:21 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:21 +0900 Subject: [Slashdotjp-dev 337] CVS update: slashjp/plugins/Bookmark/templates Message-ID: <20060712113621.AA5102AC09E@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:27 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:27 +0900 Subject: [Slashdotjp-dev 338] CVS update: slashjp/plugins/Console/templates Message-ID: <20060712113627.B0AB92AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:34 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:34 +0900 Subject: [Slashdotjp-dev 339] CVS update: slashjp/plugins/Daypass/templates Message-ID: <20060712113634.9E5B12AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:51 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:51 +0900 Subject: [Slashdotjp-dev 340] CVS update: slashjp/Slash/Client/lib/Slash Message-ID: <20060712113651.B149F2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:51 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:51 +0900 Subject: [Slashdotjp-dev 341] CVS update: slashjp/plugins/Ajax/htdocs/images Message-ID: <20060712113651.D59152AC0A1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 342] CVS update: slashjp/plugins/Remarks/templates Message-ID: <20060712113652.05DC72AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 343] CVS update: slashjp/plugins/ResKey/ResKey Message-ID: <20060712113652.29C002AC0A1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 344] CVS update: slashjp/plugins/ResKey/tasks Message-ID: <20060712113652.4EA492AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 345] CVS update: slashjp/plugins/ResKey/templates Message-ID: <20060712113652.736292AC0A1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 346] CVS update: slashjp/plugins/ScheduleShifts/templates Message-ID: <20060712113652.9818E2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 347] CVS update: slashjp/plugins/SearchToo/SearchToo Message-ID: <20060712113652.BD7212AC0A1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:52 +0900 Subject: [Slashdotjp-dev 348] CVS update: slashjp/plugins/SearchToo/templates Message-ID: <20060712113652.E13882AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:53 +0900 Subject: [Slashdotjp-dev 349] CVS update: slashjp/plugins/Tags/templates Message-ID: <20060712113653.120422AC0A2@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:53 +0900 Subject: [Slashdotjp-dev 350] CVS update: slashjp/plugins/Unsubscribe/templates Message-ID: <20060712113653.36A142AC0A1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:53 +0900 Subject: [Slashdotjp-dev 351] CVS update: slashjp/plugins/Validator/templates Message-ID: <20060712113653.5B8ED2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:53 +0900 Subject: [Slashdotjp-dev 352] CVS update: slashjp/plugins/Validator/validator Message-ID: <20060712113653.7F6BA2AC0A2@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:53 +0900 Subject: [Slashdotjp-dev 353] CVS update: slashjp/tagboxes/TagCountUser Message-ID: <20060712113653.A48CC2AC0A3@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:36:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:36:53 +0900 Subject: [Slashdotjp-dev 354] CVS update: slashjp/tagboxes/Top Message-ID: <20060712113653.C98EE2AC0A1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:17 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:17 +0900 Subject: [Slashdotjp-dev 355] CVS update: slashjp/Slash/Client/lib/Slash/Client Message-ID: <20060712113717.744892AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:17 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:17 +0900 Subject: [Slashdotjp-dev 356] CVS update: slashjp/plugins/ResKey/ResKey/Checks Message-ID: <20060712113717.988032AC0B1@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:17 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:17 +0900 Subject: [Slashdotjp-dev 357] CVS update: slashjp/plugins/Validator/validator/htdocs Message-ID: <20060712113717.C71522AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:23 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:23 +0900 Subject: [Slashdotjp-dev 358] CVS update: slashjp/plugins/ResKey/ResKey/Checks/AL2 Message-ID: <20060712113723.5CAF82AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:23 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:23 +0900 Subject: [Slashdotjp-dev 359] CVS update: slashjp/plugins/Validator/validator/htdocs/config Message-ID: <20060712113723.82E132AC0B2@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:23 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:23 +0900 Subject: [Slashdotjp-dev 360] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib Message-ID: <20060712113723.A9C2B2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:27 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:27 +0900 Subject: [Slashdotjp-dev 361] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML Message-ID: <20060712113727.9BFB02AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:27 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:27 +0900 Subject: [Slashdotjp-dev 362] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-MathML2-20010221 Message-ID: <20060712113727.C24762AC0B5@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:27 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:27 +0900 Subject: [Slashdotjp-dev 363] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-SVG-20010904 Message-ID: <20060712113727.E98302AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 364] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-SVG11-20030114 Message-ID: <20060712113728.194562AC0B5@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 365] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-html40-19980424 Message-ID: <20060712113728.3DF132AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 366] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-html40-971218 Message-ID: <20060712113728.6285E2AC0B5@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 367] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-html401-19991224 Message-ID: <20060712113728.874002AC0B7@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 368] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-smil-19980615 Message-ID: <20060712113728.ABDE22AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 369] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-xhtml-basic-20001219 Message-ID: <20060712113728.D06522AC0B5@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:28 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:28 +0900 Subject: [Slashdotjp-dev 370] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-xhtml1-20000126 Message-ID: <20060712113729.00EDC2AC0B7@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:29 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:29 +0900 Subject: [Slashdotjp-dev 371] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-xhtml11-20010531 Message-ID: <20060712113729.4A0B82AC0B5@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:29 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:29 +0900 Subject: [Slashdotjp-dev 372] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/REC-xhtml1-20020801 Message-ID: <20060712113729.257902AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:29 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:29 +0900 Subject: [Slashdotjp-dev 373] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/UPD-MathML2-20021015 Message-ID: <20060712113729.6F2AC2AC0B7@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:33 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:33 +0900 Subject: [Slashdotjp-dev 374] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/UPD-MathML2-20021015/iso8879 Message-ID: <20060712113733.F032D2AC0C3@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:34 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:34 +0900 Subject: [Slashdotjp-dev 375] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/UPD-MathML2-20021015/iso9573-13 Message-ID: <20060712113734.27E3D2AC011@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:37:34 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:37:34 +0900 Subject: [Slashdotjp-dev 376] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/UPD-MathML2-20021015/mathml Message-ID: <20060712113734.4F8D72AC0C7@users.sourceforge.jp> From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:36 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:36 +0900 Subject: [Slashdotjp-dev 378] CVS update: slashjp/Bundle Message-ID: <20060712114136.55E832AC0D3@users.sourceforge.jp> Index: slashjp/Bundle/.cvsignore diff -u slashjp/Bundle/.cvsignore:1.1.1.1 slashjp/Bundle/.cvsignore:1.2 --- slashjp/Bundle/.cvsignore:1.1.1.1 Wed Jan 28 06:53:50 2004 +++ slashjp/Bundle/.cvsignore Wed Jul 12 20:41:36 2006 @@ -1 +1,2 @@ Bundle-Slash-* +.lwpcookies Index: slashjp/Bundle/README diff -u slashjp/Bundle/README:1.2 slashjp/Bundle/README:1.3 --- slashjp/Bundle/README:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/Bundle/README Wed Jul 12 20:41:36 2006 @@ -1,4 +1,4 @@ -# $Id: README,v 1.2 2004/12/21 20:54:52 oliver Exp $ +# $Id: README,v 1.3 2006/07/12 11:41:36 sugi Exp $ This is a Bundle file for Slash, the code that runs Slashdot. See http://slashcode.com/ for more information. It is geared toward Slash 2.2.x and later versions, but should work fine for older versions of Index: slashjp/Bundle/Slash.pm diff -u slashjp/Bundle/Slash.pm:1.3 slashjp/Bundle/Slash.pm:1.4 --- slashjp/Bundle/Slash.pm:1.3 Fri Dec 31 21:35:42 2004 +++ slashjp/Bundle/Slash.pm Wed Jul 12 20:41:36 2006 @@ -1,10 +1,10 @@ package Bundle::Slash; # -# $Id: Slash.pm,v 1.3 2004/12/31 12:35:42 oliver Exp $ +# $Id: Slash.pm,v 1.4 2006/07/12 11:41:36 sugi Exp $ # -$Bundle::Slash::VERSION = '2.34'; +$Bundle::Slash::VERSION = '2.51'; 1; @@ -109,6 +109,15 @@ Lingua::Stem +URI::Find + +Config::General - HTML validator + +Set::IntSpan - HTML validator + +Text::Iconv - HTML validator + +Data::JavaScript::Anon - perl2js data structures =head1 DESCRIPTION @@ -119,6 +128,6 @@ and thus not installed by default, but which may become required as you edit your site configuration, are: Cache::Memcached Silly::Werder GD GD::Text GD::Graph Apache::SSI Apache::RegistryFilter GraphViz -Net::IRC Proc::ProcessTable +Net::IRC Proc::ProcessTable Net::Jabber IO::Socket::SSL =cut From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:36 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:36 +0900 Subject: [Slashdotjp-dev 377] CVS update: slashjp Message-ID: <20060712114136.31F9E2AC011@users.sourceforge.jp> Index: slashjp/AUTHORS diff -u slashjp/AUTHORS:1.2 slashjp/AUTHORS:1.3 --- slashjp/AUTHORS:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/AUTHORS Wed Jul 12 20:41:35 2006 @@ -2,8 +2,8 @@ Rob Malda malda ¡÷ slashdot.org Jonathon Pater pater ¡÷ slashdot.org - Patrick Galbraith patg ¡÷ osdn.com - Chris Nandor pudge ¡÷ osdn.com + Patrick Galbraith patg ¡÷ patg.net + Chris Nandor pudge ¡÷ ostg.com Brian Aker brian ¡÷ tangent.org Cliff Wood cliff ¡÷ slashdot.org Jamie McCarthy jamie ¡÷ mccarthy.vg @@ -15,10 +15,10 @@ rectify it.) Dave Aiello dave_aiello ¡÷ ctdata.com - Daniel "Yazz" Atlas yazz ¡÷ osdn.com + Daniel "Yazz" Atlas yazz ¡÷ ostg.com Alessio Bragadini alessio ¡÷ albourne.com Atif Ghaffar atif ¡÷ developer.ch - Dave Olszewski dave.olszewski ¡÷ osdn.com + Dave Olszewski dave.olszewski ¡÷ ostg.com Nathan Vonnahme nathan ¡÷ thethirdsector.com Bernard de Rubinat bernard ¡÷ netgames.org Steinar H. Gunderson sgunderson ¡÷ bigfoot.com @@ -36,5 +36,5 @@ chromatic chromatic ¡÷ rmci.net Dan Stahlke dans ¡÷ infoinsights.com -# $Id: AUTHORS,v 1.2 2004/12/21 20:54:52 oliver Exp $ +# $Id: AUTHORS,v 1.3 2006/07/12 11:41:35 sugi Exp $ Index: slashjp/CHANGES diff -u slashjp/CHANGES:1.2 slashjp/CHANGES:1.3 --- slashjp/CHANGES:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/CHANGES Wed Jul 12 20:41:36 2006 @@ -1,4 +1,4 @@ -# $Id: CHANGES,v 1.2 2004/12/21 20:54:52 oliver Exp $ +# $Id: CHANGES,v 1.3 2006/07/12 11:41:36 sugi Exp $ (We should update this file before we release a 2.3.0 -- there have been six versions since 2.2.0. I believe 2.2.1 thru 2.2.6 were all bugfix Index: slashjp/INSTALL diff -u slashjp/INSTALL:1.3 slashjp/INSTALL:1.4 --- slashjp/INSTALL:1.3 Fri Dec 31 21:35:42 2004 +++ slashjp/INSTALL Wed Jul 12 20:41:36 2006 @@ -76,8 +76,9 @@ 1. Install MySQL. - Please refer to MySQL documentation for compilation and/or - installation notes for any questions with this process. + If it is already installed, doublecheck that its version is at least + the minimum required (see "REQUIREMENTS"). If you have questions + about the installation process, please refer to MySQL documentation. Slash requires that your MySQL server run in the GMT timezome. Find your global my.cnf file (probably "/etc/my.cnf" or @@ -86,8 +87,8 @@ timezone = GMT - Start MySQL (it must be running for the installation of Perl modules - and Slash). + Start, or restart, MySQL (it must be running for the installation of + Perl modules and Slash). Create a database to be used by Slash. @@ -99,8 +100,8 @@ 2. Install perl. - perl is likely already installed on your machine; make sure its - version is at least the minimum required (see "REQUIREMENTS"). + perl is likely already installed on your machine; doublecheck that + its version is at least the minimum required (see "REQUIREMENTS"). 3. Install Apache and mod_perl. @@ -133,13 +134,7 @@ are not yet installed. However, some Perl modules will not install without Apache and mod_perl installed. If you wish, come back and run "make test" after installing here, and then installing the Perl - modules, to make sure everything is OK. Also, as of January 2002, a - "make test" has thrown spurious errors for several months because of - a persistent minor bug; if you see "Can't locate object method 'new' - via package 'URI::URL'", read this: - - + modules, to make sure everything is OK. NOTE: If you know what you're doing, Slash will work with a DSO Apache. Be sure you're on the latest versions of Apache and mod_perl @@ -207,7 +202,7 @@ ---- Unsatisfied dependencies detected during [FOO/Bar-1.23.tar.gz] ----- Foobar::Baz Shall I follow them and prepend them to the queue - of modules we are processing right now? [yes] + of modules we are processing right now? [yes] That's normal; just hit return. @@ -412,8 +407,9 @@ 7. Start it up. After installation of the site is done, and Apache has been stopped - and started (do NOT try to restart Apache, but do a full stop and - start), run slashd. This should be done via the init script: + and started (do not try to "restart" Apache, but rather do a full + stop and start), then run slashd. This should be done via the init + script: /etc/init.d/slash start @@ -496,11 +492,11 @@ RAM or 5 MB? Slashdot, and some other Slash sites we're hosting, are currently using - boa 0.94.14rc17 () for images. Boa is fast and has - a small footprint. It's easy to build ("./configure && make") but you - have to install it yourself by copying the binary and mkdir'ing a little - tree wherever you want it. We did roughly this. Your mileage may vary. - This sets up an alternate server just for images on port 8080, and sets + boa 0.94.14rc17 (http://www.boa.org/) for images. Boa is fast and has a + small footprint. It's easy to build ("./configure && make") but you have + to install it yourself by copying the binary and mkdir'ing a little tree + wherever you want it. We did roughly this. Your mileage may vary. This + sets up an alternate server just for images on port 8080, and sets Slash's imagedir var to point to it. Your apache will still serve images at the old URLs if anyone requests them, but nobody will, because your site's pages will all point to boa: @@ -540,6 +536,17 @@ before beginning. We are not responsible for any loss of data or functionality. + Slash 1.0 -> Slash 2.2 + You've got a site running Slash 1.0, from 2001? We're so sorry to hear + that. + + Please read the complete documentation of utils/slash1toslash2.2. We + believe it will convert your database from Slash 1.0 to a new Slash 2.2 + database, but it hasn't been tested in some time. The program + documentation (which can be read with perldoc) details exactly what + process it follows to do the conversion, so you can attempt to do it by + hand if you prefer. + Slash 2.0 -> Slash 2.2 Slash 2.2 is a major upgrade from Slash 2.0. It takes a little bit of work to get it going. @@ -707,51 +714,59 @@ % template-tool -u VIRTUAL_USER -s LIST Slash 2.2.6 -> Slash CVS - Use the sql/mysql/upgrades file; see "VERSIONS", "CVS tags", below. - - Slash 1.0 -> Slash 2.2 - Please read the complete documentation of utils/slash1toslash2.2. It is - a program that will convert your database from Slash 1.0 to a new Slash - 2.2 database. The program documentation (which can be read with perldoc) - details exactly what process it follows to do the conversion, so you can - attempt to do it by hand if you prefer. + Use the sql/mysql/upgrades file; see "VERSIONS", "CVS tags", below. This + file is human-readable and very long. You can upgrade a 2.2.6 to the + latest CVS by methodically applying every step in this file, but it is + tedious and requires an engaged human brain reading the comments (i.e., + don't "mysql slash < upgrades", that will fail miserably). + + Slash CVS -> later Slash CVS + Again, use the sql/mysql/upgrades file (and the caveat just mentioned + still applies). Start from the CVS tag you left off at, and proceed to + the CVS tag you upgraded to (which should be the end of the file). If + you're not sure which tag you left off at, you might check the var + 'cvs_tag_currentcode', which will contain the right value if you last + updated after September 2005. + + In general, you should stop apache and slashd, do a "make install", + apply the upgrades file a line at a time for each Slash site, run + "template-tool -U -u virtusename" and "symlink-tool -U -u virtusername" + for each Slash site, and then start slashd and apache back up. REQUIREMENTS Software Requirements Below, we list the main software components needed. The recommended version is noted, along with the earliest version that has been tested - (or is expected) to work. The earliest versions are not necessarily - supported, but should work. perl 5.6.0 is supported, but MySQL 3.22 is - not. + (or is expected) to work. The earliest versions are not recommended or + supported, but should work. perl - Version 5.6.1 (5.6.0). [NOTE: perl 5.6.0 may have some problems. - 5.6.1 is recommended.] + Version 5.8.6 (5.6.1). http://www.cpan.org/ - We believe everything works fine with perl 5.8.x, x >= 1, and have - several small Slash installations on it, but we have not tested - Unicode thoroughly, nor have we run Slashdot on it yet. - MySQL - Version 4.0.12 (4.0.4). + Version 4.1.18 (4.0.12). http://www.mysql.com/ MySQL 3.23.x is no longer supported, as of CVS tag T_2_5_0_33 - (October 18, 2004). + (October 18, 2004). Slashdot has been running on MySQL 4.1.x with no + problems, so we now recommend that, but 4.0.x works as well. We have + been testing 5.0.x for months but currently, no production sites run + it. Apache - Version 1.3.29 (1.3.6). + Version 1.3.33. http://httpd.apache.org/ - Do not use Apache 1.3.28. It has a nasty bug in it that causes Slash - to talk to the web browser as though it is the database server. + Since most of Apache 1.3.x's recent releases included security + fixes, we wouldn't recommend running an earlier version. As far as + we know, Slash is not compatible with Apache 2.x. mod_perl - Version 1.29 (1.21). + Version 1.29. http://perl.apache.org/ @@ -979,8 +994,8 @@ fully understand MySQL permissions, don't guess; start your reading here: - + http://www.mysql.com/documentation/mysql/bychapter/manual_MySQL_ + Database_Administration.html#Privilege_system * mod_gzip @@ -1084,5 +1099,5 @@ /usr/local/slash/site/yoursitename". VERSION - $Id: INSTALL,v 1.3 2004/12/31 12:35:42 oliver Exp $ + $Id: INSTALL,v 1.4 2006/07/12 11:41:36 sugi Exp $ Index: slashjp/INSTALL.debian diff -u slashjp/INSTALL.debian:1.2 slashjp/INSTALL.debian:1.3 --- slashjp/INSTALL.debian:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/INSTALL.debian Wed Jul 12 20:41:36 2006 @@ -55,5 +55,5 @@ DateManip libdate-manip-perl VERSION - $Id: INSTALL.debian,v 1.2 2004/12/21 20:54:52 oliver Exp $ + $Id: INSTALL.debian,v 1.3 2006/07/12 11:41:36 sugi Exp $ Index: slashjp/INSTALL.rpm diff -u slashjp/INSTALL.rpm:1.2 slashjp/INSTALL.rpm:1.3 --- slashjp/INSTALL.rpm:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/INSTALL.rpm Wed Jul 12 20:41:36 2006 @@ -32,5 +32,5 @@ 3. Restart Apache. VERSION - $Id: INSTALL.rpm,v 1.2 2004/12/21 20:54:52 oliver Exp $ + $Id: INSTALL.rpm,v 1.3 2006/07/12 11:41:36 sugi Exp $ Index: slashjp/INSTALL.solaris diff -u slashjp/INSTALL.solaris:1.2 slashjp/INSTALL.solaris:1.3 --- slashjp/INSTALL.solaris:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/INSTALL.solaris Wed Jul 12 20:41:36 2006 @@ -40,6 +40,6 @@ Continue the installation as suggestion in the main INSTALL documentation. VERSION - $Id: INSTALL.solaris,v 1.2 2004/12/21 20:54:52 oliver Exp $ + $Id: INSTALL.solaris,v 1.3 2006/07/12 11:41:36 sugi Exp $ __END__ Index: slashjp/MANIFEST diff -u slashjp/MANIFEST:1.3 slashjp/MANIFEST:1.4 --- slashjp/MANIFEST:1.3 Fri Dec 31 21:35:42 2004 +++ slashjp/MANIFEST Wed Jul 12 20:41:36 2006 @@ -435,7 +435,6 @@ themes/slashcode/templates/mainmenu;misc;default themes/slashcode/templates/messages;users;default themes/slashcode/templates/metaModerate;metamod;default -themes/slashcode/templates/miniAdminMenu;users;default themes/slashcode/templates/modCommentLog;misc;default themes/slashcode/templates/mod_footer;comments;default themes/slashcode/templates/mod_header;comments;default Index: slashjp/Makefile diff -u slashjp/Makefile:1.3 slashjp/Makefile:1.4 --- slashjp/Makefile:1.3 Fri Dec 31 21:35:42 2004 +++ slashjp/Makefile Wed Jul 12 20:41:36 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2003 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Makefile,v 1.3 2004/12/31 12:35:42 oliver Exp $ +# $Id: Makefile,v 1.4 2006/07/12 11:41:36 sugi Exp $ ## ## Makefile -- Current one for Slash @@ -37,14 +37,15 @@ UNAME = `uname` MAKE = make -s -# Plugins (any directory in plugins/) -PLUGINS = `find . -name CVS -prune -o -type d -name [a-zA-Z]\* -maxdepth 1 -print` +# Subdirectories excl. CVS in the current directory (like plugins/ or tagboxes/) +SUBDIRS = `find . -maxdepth 1 -name CVS -prune -o -type d -name [a-zA-Z]\* -print` # Perl scripts, grouped by directory. BINFILES = `find bin -name CVS -prune -o -name [a-zA-Z]\* -type f -print` SBINFILES = `find sbin -name CVS -prune -o -name [a-zA-Z]\* -type f -print` THEMEFILES = `find themes -name CVS -prune -o -name [a-zA-z]\*.pl -print` PLUGINFILES = `find plugins -name CVS -prune -o -name [a-zA-Z]\*.pl -print` +TAGBOXFILES = `find tagboxes -name CVS -prune -o -name [a-zA-Z]\*.pl -print` # What do we use to invoke perl? REPLACEWITH = `$(PERL) -MConfig -e 'print quotemeta($$Config{startperl})' | sed 's/@/\\@/g'` @@ -58,7 +59,7 @@ INSTALLSITELIB=`$(PERL) -MConfig -e 'print "$(BUILDROOT)/$$Config{installsitelib}"'` INSTALLMAN3DIR=`$(PERL) -MConfig -e 'print "$(BUILDROOT)/$$Config{installman3dir}"'` -.PHONY : all plugins slash install +.PHONY : all plugins tagboxes slash install # install the shared object file into Apache # We should run a script on the binaries to get the right @@ -76,7 +77,25 @@ plugins: @echo "=== INSTALLING SLASH PLUGINS ===" @(cd plugins; \ - for a in $(PLUGINS); do \ + for a in $(SUBDIRS); do \ + (cd $$a; \ + echo == $$PWD; \ + if [ -f Makefile.PL ]; then \ + if [ ! "$(RPM)" ] ; then \ + $(PERL) Makefile.PL; \ + $(MAKE) install UNINST=1;\ + else \ + echo " - Performing an RPM build."; \ + $(PERL) Makefile.PL INSTALLSITEARCH=$(INSTALLSITEARCH) INSTALLSITELIB=$(INSTALLSITELIB) INSTALLMAN3DIR=$(INSTALLMAN3DIR); \ + $(MAKE) install UNINST=1; \ + fi; \ + fi); \ + done) + +tagboxes: + @echo "=== INSTALLING SLASH TAGBOXES ===" + @(cd tagboxes; \ + for a in $(SUBDIRS); do \ (cd $$a; \ echo == $$PWD; \ if [ -f Makefile.PL ]; then \ @@ -93,7 +112,7 @@ all: install -install: slash plugins +install: slash plugins tagboxes # Create all necessary directories. $(INSTALL) -d \ @@ -101,6 +120,7 @@ $(SLASH_PREFIX)/httpd/ \ $(SLASH_PREFIX)/themes/ \ $(SLASH_PREFIX)/plugins/ \ + $(SLASH_PREFIX)/tagboxes/ \ $(SLASH_PREFIX)/sbin \ $(SLASH_PREFIX)/sql/ \ $(SLASH_PREFIX)/sql/mysql/ @@ -111,13 +131,15 @@ # section of the Makefile would need to be rewritten to do this sanely # and there just isn't the time for that right now. # - # Install the plugins...(will also install kruft like CVS/ and blib/ - # directories if they are around. Maybe a smarter copying procedure - # is called for, here?) + # Install the plugins and tagboxes. Will also install kruft like CVS/ + # and blib/ directories if they are around. Maybe a smarter copying + # procedure is called for, here?) # # Note: Many users of Slash have taken to symlinking the plugins and themes # directories into $(SLASH_PREFIX) from their checked-out CVS trees. We # should try to check for this in the future and behave accordingly. + # (Update, 2006-05-06: no, we're not going to check for that. Editing a + # CVS checkout is great, but push it live with a 'make install' please.) # # OpenBSD needs "-R" here instead of "-rv". Its manpage notes: # Historic versions of the cp utility had a -r option. This implementation @@ -126,7 +148,9 @@ # (cd plugins; $(MAKE) clean) $(CP) -r plugins/* $(SLASH_PREFIX)/plugins - # Now all other themes + (cd tagboxes; $(MAKE) clean) + $(CP) -r tagboxes/* $(SLASH_PREFIX)/tagboxes + # Now all the themes $(CP) -r themes/* $(SLASH_PREFIX)/themes # Insure we use the proper Perl interpreter and prefix in all scripts that @@ -137,13 +161,14 @@ sbinfiles=$(SBINFILES); \ themefiles=$(THEMEFILES); \ pluginfiles=$(PLUGINFILES); \ + tagboxfiles=$(TAGBOXFILES); \ if [ "$$replacewith" != "\#\!\/usr\/bin\/perl" ]; then \ replace=1; \ replacestr='(using $(PERL))'; \ else \ replace=0; \ fi; \ - for f in $$binfiles $$sbinfiles $$themefiles $$pluginfiles; do \ + for f in $$binfiles $$sbinfiles $$themefiles $$pluginfiles $$tagboxfiles; do \ n=$(SLASH_PREFIX)/$$f; \ $(INSTALL) -d $(SLASH_PREFIX)/$$d; \ if [ $$replace ]; then \ @@ -232,6 +257,7 @@ chown -R $(USER):$(GROUP) $(SLASH_PREFIX)/bin chown -R $(USER):$(GROUP) $(SLASH_PREFIX)/sql chown -R $(USER):$(GROUP) $(SLASH_PREFIX)/plugins + chown -R $(USER):$(GROUP) $(SLASH_PREFIX)/tagboxes # Add a @ to suppress output of the echo's @echo "+--------------------------------------------------------+"; \ echo "| All done. |"; \ @@ -246,7 +272,6 @@ echo "| Thanks for installing Slash. |"; \ echo "+--------------------------------------------------------+"; \ - reload: install apachectl stop apachectl start @@ -256,6 +281,7 @@ (cd Slash; if [ ! -f Makefile ]; then perl Makefile.PL; fi; $(MAKE) clean) (rm Slash/Apache/Apache.xs Slash/Apache/User/User.xs) (cd plugins; $(MAKE) clean) + (cd tagboxes; $(MAKE) clean) find ./ | grep \# | xargs rm dist: $(DISTVNAME).tar$(SUFFIX) Index: slashjp/Makefile.NEW diff -u slashjp/Makefile.NEW:1.2 slashjp/Makefile.NEW:1.3 --- slashjp/Makefile.NEW:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/Makefile.NEW Wed Jul 12 20:41:36 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Makefile.NEW,v 1.2 2004/12/21 20:54:52 oliver Exp $ +# $Id: Makefile.NEW,v 1.3 2006/07/12 11:41:36 sugi Exp $ ## ## Makefile -- Current one for Slash @@ -32,7 +32,7 @@ CP = cp # Plugins (any directory in plugins/) -PLUGINS = `find . -name CVS -prune -o -type d -maxdepth 1 -print` +PLUGINS = `find . -maxdepth 1 -name CVS -prune -o -type d -print` # Perl scripts, grouped by directory. BINFILES = `find bin -name CVS -prune -o -type f -print` Index: slashjp/README diff -u slashjp/README:1.2 slashjp/README:1.3 --- slashjp/README:1.2 Wed Dec 22 05:54:52 2004 +++ slashjp/README Wed Jul 12 20:41:36 2006 @@ -131,9 +131,9 @@ The information below applies to everything in this distribution, except where noted. - Copyright 1997-2004 by Open Source Development Network. + Copyright 1997-2005 by Open Source Technology Group. - http://www.osdn.com/ + http://www.ostg.com/ Slash is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -151,5 +151,5 @@ 02111-1307, USA. VERSION - $Id: README,v 1.2 2004/12/21 20:54:52 oliver Exp $ + $Id: README,v 1.3 2006/07/12 11:41:36 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:36 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:36 +0900 Subject: [Slashdotjp-dev 379] CVS update: slashjp/Slash/Apache Message-ID: <20060712114136.A64722AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Apache/Apache.pm diff -u slashjp/Slash/Apache/Apache.pm:1.4 slashjp/Slash/Apache/Apache.pm:1.5 --- slashjp/Slash/Apache/Apache.pm:1.4 Tue Apr 26 19:40:44 2005 +++ slashjp/Slash/Apache/Apache.pm Wed Jul 12 20:41:36 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Apache.pm,v 1.4 2005/04/26 10:40:44 oliver Exp $ +# $Id: Apache.pm,v 1.5 2006/07/12 11:41:36 sugi Exp $ package Slash::Apache; @@ -18,16 +18,17 @@ require DynaLoader; require AutoLoader; -use vars qw($REVISION $VERSION @ISA $USER_MATCH); +use vars qw($REVISION $VERSION @ISA $USER_MATCH $DAYPASS_MATCH); @ISA = qw(DynaLoader); $VERSION = '2.003000'; # v2.3.0 -($REVISION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; +($REVISION) = ' $Revision: 1.5 $ ' =~ /\$Revision:\s+([^\s]+)/; $USER_MATCH = qr{ \buser=(?! # must have user, but NOT ... (?: nobody | %[20]0 )? # nobody or space or null or nothing ... (?: \s | ; | $ ) # followed by whitespace, ;, or EOS )}x; +$DAYPASS_MATCH = qr{\bdaypassconfcode=}; bootstrap Slash::Apache $VERSION; @@ -241,6 +242,8 @@ $slashdb->{_dbh}->disconnect; } +# This handler is called in the first Apache phase, post-read-request. +# # This can be used in conjunction with mod_proxy_add_forward or somesuch, # if you use a frontend/backend Apache setup, where all requests come # from 127.0.0.1 or some other predictable IP number(s). For speed, we @@ -287,16 +290,18 @@ # That probably didn't work so let's get that data the hard way. my $r = Apache->request; + return 0 if !$r; my $subr = $r->lookup_uri($r->uri); - my $https_on = ($subr && $subr->subprocess_env('HTTPS') eq 'on') - ? 1 : 0; - return 1 if $https_on; + if ($subr) { + my $se = $subr->subprocess_env('HTTPS'); + return 1 if $se && $se eq 'on'; # https is on + } - return 1 - if $r->header_in('X-SSL-On') eq 'yes'; + my $x = $r->header_in('X-SSL-On'); + return 1 if $x && $x eq 'yes'; - # Nope, it's not SSL. We're out of ideas, if the above didn't - # work we must not be on SSL. + # We're out of ideas. If the above didn't work we must not be + # on SSL. return 0; } @@ -335,13 +340,19 @@ my $gSkin = getCurrentSkin(); my $uri = $r->uri; - my $is_user = $r->header_in('Cookie') =~ $USER_MATCH; + my $cookie = $r->header_in('Cookie'); + my $is_user = $cookie =~ $USER_MATCH; + my $has_daypass = 0; + if (!$is_user) { + if ($constants->{daypass} && $cookie =~ $DAYPASS_MATCH) { + $has_daypass = 1; + } + } - # harmful if deciding skin on directory - #if ($gSkin->{rootdir}) { - # my $path = URI->new($gSkin->{rootdir})->path; - # $uri =~ s/^\Q$path//; - #} + if ($gSkin->{rootdir}) { + my $path = URI->new($gSkin->{rootdir})->path; + $uri =~ s/^\Q$path//; + } # Comment this in if you want to try having this do the right # thing dynamically @@ -349,17 +360,13 @@ # my $dbon = $slashdb->sqlConnect(); my $dbon = dbAvailable(); - # URI ends with a slash and is equal to the skin's rootdir - if ($uri =~ m|(.*)/$| && URI->new($gSkin->{rootdir})->path eq $1 - && $gSkin->{index_handler} ne 'IGNORE') { + if ($uri eq '/' && $gSkin->{index_handler} ne 'IGNORE') { my $basedir = $constants->{basedir}; # $USER_MATCH defined above - if ($dbon && $is_user) { - $r->uri( $uri . $gSkin->{index_handler} ); + if ($dbon && ($is_user || $has_daypass)) { + $r->uri("/$gSkin->{index_handler}"); $r->filename("$basedir/$gSkin->{index_handler}"); - # URI->filname conversion done, don't continue - $r->set_handlers(PerlTransHandler => undef); return OK; } elsif (!$dbon) { # no db (you may wish to symlink index.shtml to your real @@ -386,6 +393,64 @@ } } + # match /section/ or /section + if ($uri =~ m|^/(\w+)/?$|) { + my $key = $1; + + if (!$dbon) { + $r->uri('/index.shtml'); + return DECLINED; + } + + my $slashdb = getCurrentDB(); + my $new_skin = $slashdb->getSkin($key); + my $new_skid = $new_skin->{skid} || $constants->{mainpage_skid}; +#print STDERR scalar(localtime) . " $$ IndexHandler B new_skid=$new_skid\n"; + setCurrentSkin($new_skid); + $gSkin = getCurrentSkin(); + + my $index_handler = $gSkin->{index_handler}; + if ($index_handler ne 'IGNORE') { + my $basedir = $constants->{basedir}; + + # $USER_MATCH defined above + if ($dbon && ($is_user || $has_daypass)) { + $r->args("section=$key"); + # For any directory which can be accessed by a + # logged-in user in the URI form /foo or /foo/, + # but which is not a skin's directory, there + # is a problem; we cannot simply bounce the uri + # back to /index.pl or whatever, since the + # index handler will not recognize the section + # key argument above and will just present the + # ordinary homepage. I don't know the best way + # to handle this situation at the moment, so + # instead I'm hardcoding in the solution for the + # most common problem. - Jamie 2004/07/17 + if ($key eq "faq" || $key eq "palm") { + $r->uri("/$key/index.shtml"); + } elsif ($key eq "docs" + || $key eq "privaterss") { + $r->uri("/$key/"); + } else { + $r->uri("/$index_handler"); + } + $r->filename("$basedir/$index_handler"); + return OK; + } else { + # user not logged in + + # consider using File::Basename::basename() here + # for more robustness, if it ever matters -- pudge + my($base) = split(/\./, $index_handler); + $r->uri("/$key/$base.shtml"); + $r->filename("$basedir/$key/$base.shtml"); + writeLog('shtml'); + return OK; + } + } + } + if ($uri eq '/authors.pl') { my $filename = $r->filename; my $basedir = $constants->{basedir}; @@ -407,13 +472,17 @@ return OK; } - # redirect to static if not a user, and + # redirect to static if + # * not a user, nor a daypass holder, + # and # * var is on # * is article.pl # * no page number > 1 specified # * sid specified # * referrer exists AND is external to our site - if ($constants->{referrer_external_static_redirect} && !$is_user && $uri eq '/article.pl') { + if ($constants->{referrer_external_static_redirect} + && !$is_user && !$has_daypass + && $uri eq '/article.pl') { my $referrer = $r->header_in("Referer"); my $referrer_domain = $constants->{referrer_domain} || $gSkin->{basedomain}; my $the_request = $r->the_request; @@ -434,14 +503,6 @@ } } - # .pl in section dirs are served by scripts in basedir - if( $uri =~ m|^.+/(\w+\.pl)$| ){ - my $basedir = $constants->{basedir}; - $r->filename("$basedir/$1"); - $r->set_handlers(PerlTransHandler => undef); - return OK; - } - if (!$dbon && $uri !~ /\.(?:shtml|html|jpg|gif|png|rss|rdf|xml|txt|css)$/) { # if db is off we don't necessarily have access to constants # this means we change the URI and return DECLINED which lets From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:36 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:36 +0900 Subject: [Slashdotjp-dev 380] CVS update: slashjp/Slash/Apache/Banlist Message-ID: <20060712114136.CE8C52AC011@users.sourceforge.jp> Index: slashjp/Slash/Apache/Banlist/Banlist.pm diff -u slashjp/Slash/Apache/Banlist/Banlist.pm:1.2 slashjp/Slash/Apache/Banlist/Banlist.pm:1.3 --- slashjp/Slash/Apache/Banlist/Banlist.pm:1.2 Wed Dec 22 18:13:31 2004 +++ slashjp/Slash/Apache/Banlist/Banlist.pm Wed Jul 12 20:41:36 2006 @@ -1,13 +1,14 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Banlist.pm,v 1.2 2004/12/22 09:13:31 oliver Exp $ +# $Id: Banlist.pm,v 1.3 2006/07/12 11:41:36 sugi Exp $ + +# This handler is called in the fourth Apache phase, access control. package Slash::Apache::Banlist; use strict; use Apache::Constants qw(:common); -use Digest::MD5 'md5_hex'; use Slash; use Slash::Display; @@ -16,7 +17,7 @@ use vars qw($VERSION); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; sub handler { my($r) = @_; @@ -27,32 +28,35 @@ # Ok, this will make it so that we can reliably use Apache->request Apache->request($r); - my $hostip = $r->connection->remote_ip; - my($cur_ip, $cur_subnet) = get_ipids($hostip, 1); - my($cur_ipid, $cur_subnetid) = get_ipids($hostip); + # Get some information about the IP this request is coming from. + my $hostip = $r->connection->remote_ip; + my($cur_ip, $cur_subnet) = get_srcids({ ip => $hostip }, + { no_md5 => 1, return_only => [qw( ip subnet )] }); + my($cur_srcid_ip, $cur_srcid_subnet) = get_srcids({ ip => $hostip }, + { return_only => [qw( ip subnet )] }); +#print STDERR scalar(localtime) . " hostip='$hostip' cur_ip='$cur_ip' cur_subnet='$cur_subnet' cur_srcid_ip='$cur_srcid_ip' cur_srcid_subnet='$cur_srcid_subnet'\n"; + # Set up DB objects. my $slashdb = getCurrentDB(); my $reader_user = $slashdb->getDB('reader'); - my $reader = getObject('Slash::DB', { virtual_user => $reader_user }); - $reader->sqlConnect(); - - my $is_rss = $r->uri =~ m{( - \.(?:xml|rss|rdf)$ - | - content_type=rss - )}x; # also check for content_type in POST? + $reader->sqlConnect; - my $is_palm = $r->uri =~ /^\/palm/; - - # check for ban - my $banlist = $reader->getBanList(); - if ($banlist->{$cur_ipid} || $banlist->{$cur_subnetid}) { + # Check what kind of access this is. + + my($is_rss, $is_palm, $feed_type) = _check_rss_and_palm($r); + + # Abort this Apache request if this IP address is outright banned. + + my $banlist = $reader->getBanList; +#use Data::Dumper; $Data::Dumper::Sortkeys=1; +#print STDERR "cur_srcid_ip='$cur_srcid_ip' cur_srcid_subnet='$cur_srcid_subnet' banlist: " . Dumper($banlist); + if ($banlist->{$cur_srcid_ip} || $banlist->{$cur_srcid_subnet}) { + _create_banned_user($hostip); # Send a special "you are banned" page if the user is # hitting RSS. -print STDERR scalar(localtime) . " Banlist.pm $$ $hostip " . $r->method . " " . $r->uri . " returning FORBIDDEN for ipid '$banlist->{$cur_ipid}'\n"; - return _send_rss($r, 'ban') if $is_rss; + return _send_rss($r, 'ban', $cur_srcid_ip, $feed_type) if $is_rss; # Send our usual "you are banned" page, whether the user # is on palm or not. It's mostly text so palm users # should not have a problem with it. @@ -65,33 +69,75 @@ return FORBIDDEN; } - # check for RSS abuse - my $rsslist = $reader->getNorssList(); - if ($is_rss && ($rsslist->{$cur_ipid} || $rsslist->{$cur_subnet})) { - return _send_rss($r, 'abuse', $cur_ipid); + # Send a special "RSS banned" page if this IP address is banned + # from reading RSS. + if ($is_rss) { + my $rsslist = $reader->getNorssList; + if ($rsslist->{$cur_srcid_ip} || $rsslist->{$cur_srcid_subnet}) { + _create_banned_user($hostip); + return _send_rss($r, 'abuse', $cur_srcid_ip, $feed_type); + } } - # check for Palm abuse - my $palmlist = $reader->getNopalmList(); - if ($is_palm && ($palmlist->{$cur_ipid} || $palmlist->{$cur_subnet})) { - $r->custom_response(FORBIDDEN, - slashDisplay('bannedtext_palm', - { ip => $cur_ip }, - { Return => 1 } - ) - ); - return FORBIDDEN; + # Send a special "Palm banned" page if this IP addresss is banned + # from reading Palm pages. + if ($is_palm) { + my $palmlist = $reader->getNopalmList; + if ($palmlist->{$cur_srcid_ip} || $palmlist->{$cur_subnet}) { + _create_banned_user($hostip); + $r->custom_response(FORBIDDEN, + slashDisplay('bannedtext_palm', + { ip => $cur_ip }, + { Return => 1 } + ) + ); + return FORBIDDEN; + } } + # The IP address is not banned and can proceed. return OK; } +# Now we need to create a user hashref for that global +# current user, so these fields of accesslog get written +# correctly when we log this attempted hit. We do this +# dummy hashref with the bare minimum of values that we need, +# instead of going through prepareUser(), because this is +# much, much faster. +sub _create_banned_user { + my($hostip) = @_; + my($ipid, $subnetid) = get_ipids($hostip); + my $user = { + uid => getCurrentStatic('anonymous_coward_uid'), + ipid => $ipid, + subnetid => $subnetid, + }; + createCurrentUser($user); +} + + +sub _check_rss_and_palm { + my($r) = @_; + my $is_rss = $r->uri =~ m{( + \.(xml|rss|rdf|atom)$ + | + content_type=(rss|atom) + )}x; + my $feed_type = $1 || $2 || 'rss'; + $feed_type = 'rss' unless $feed_type eq 'atom'; + + # XXX Should we also check for content_type in POST? + my $is_palm = $r->uri =~ /^\/palm/; + return($is_rss, $is_palm, $feed_type); +} + sub _send_rss { - my($r, $type, $ipid) = @_; + my($r, $type, $srcid_ip, $feed_type) = @_; http_send({ content_type => 'text/xml', status => 202, - content => _get_rss_msg($type, $ipid), + content => _get_rss_msg($type, $srcid_ip, $feed_type), }); return DONE; @@ -101,27 +147,34 @@ # templates don't work with Slash::XML right now, # and redirecting will cause *more* traffic than # just spitting it out here; so cache it in $RSS_* +# XXX that really should be a cache that eventually expires my(%RSS); sub _get_rss_msg { - my($type, $ipid) = @_; + my($type, $srcid_ip, $feed_type) = @_; $type ||= 'abuse'; - $ipid ||= '(unknown)'; + $srcid_ip ||= '(unknown)'; + $feed_type ||= 'rss'; - return $RSS{$type} if exists $RSS{$type}; + return $RSS{$type}{$srcid_ip} if exists $RSS{$type}{$srcid_ip}; # template puts data in $items my $items = []; slashDisplay('bannedtext_rss', { - items => $items, - type => $type, - ipid => $ipid, + items => $items, + type => $type, + srcid_ip => $srcid_ip, }, { Return => 1 }); - return $RSS{$type} = xmlDisplay(rss => { + $RSS{$type}{$srcid_ip} = xmlDisplay($feed_type => { rdfitemdesc => 1, items => $items, }, { Return => 1 } ); + if (!$RSS{$type}{$srcid_ip}) { + # Just a quick sanity error check. + errorLog("xmlDisplay for type='$type' srcid_ip='$srcid_ip' empty"); + } + return $RSS{$type}{$srcid_ip}; } } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:36 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:36 +0900 Subject: [Slashdotjp-dev 381] CVS update: slashjp/Slash/Apache/Log Message-ID: <20060712114136.EF0942AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Apache/Log/Log.pm diff -u slashjp/Slash/Apache/Log/Log.pm:1.3 slashjp/Slash/Apache/Log/Log.pm:1.4 --- slashjp/Slash/Apache/Log/Log.pm:1.3 Fri Dec 31 21:35:43 2004 +++ slashjp/Slash/Apache/Log/Log.pm Wed Jul 12 20:41:36 2006 @@ -1,17 +1,16 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Log.pm,v 1.3 2004/12/31 12:35:43 oliver Exp $ +# $Id: Log.pm,v 1.4 2006/07/12 11:41:36 sugi Exp $ package Slash::Apache::Log; use strict; use Slash::Utility; use Apache::Constants qw(:common); -use File::Spec::Functions; # for clampe_stats, remove when done use vars qw($VERSION); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # AMY: Leela's gonna kill me. # BENDER: Naw, she'll probably have me do it. @@ -34,17 +33,8 @@ my $uri = $r->uri; my $dat = $r->err_header_out('SLASH_LOG_DATA'); - # Added this so that small sites would not have admin logins - # recorded in their stats. -Brian - - # so it will still log it if the admin DOES request - # to admin.pl? i thought you wanted it to NOT log - # requests to admin.pl? should the !~ be =~ ? - # or am i just not thinking clearly? -- pudge - - if (!$constants->{log_admin} && $uri !~ /admin\.pl/ ) { - return OK if getCurrentUser('is_admin'); - } + # There used to be some (broken) logic here involving the + # log_admin var, but that's been moved to createLog(). createLog($uri, $dat, $r->status); @@ -64,11 +54,12 @@ my($r) = @_; my $user = getCurrentUser(); + my $constants = getCurrentStatic(); + return if !$user || !$user->{uid} || $user->{is_anon}; my $user_update = undef; my $slashdb = getCurrentDB(); - my $constants = getCurrentStatic(); # First check to see if this is an admin who sent a password # in cleartext. If so and if we want to flag that, flag it @@ -88,13 +79,15 @@ # this is an admin who just sent a password in the clear. # There are other less-important things that might get updated # but none of them matters enough to continue processing. - if ($op eq 'image' and !$user_update->{admin_clearpass}) { + if ($op eq 'image' && !$user_update->{admin_clearpass}) { # print STDERR scalar(gmtime) . " $$ UserLog short-circuit image\n"; return ; } # For the below logic, note that if we're on an image hit, # page_buying will be false. + # Err, and that doesn't matter since if we're on an image, + # we already returned. So I'm not sure why I wrote that. if ($constants->{subscribe} && ($user->{is_subscriber} || !$constants->{subscribe_hits_only}) ) { @@ -106,6 +99,9 @@ my @gmt = gmtime; my $today = sprintf("%04d%02d%02d", $gmt[5]+1900, $gmt[4]+1, $gmt[3]); + # See the code near the end of MySQL.pm _getUser_do_selects() + # which forces $user->{lastclick} to be in the numeric format + # originally used by the MySQL 4.0 TIMESTAMP column type. if ($today eq substr($user->{lastclick}, 0, 8)) { # User may or may not be a subscriber, and may or may not # be buying this page. The day has not rolled over. @@ -145,13 +141,6 @@ } $slashdb->setUser($user->{uid}, $user_update) if $user_update && %$user_update; - # stats for clampe - if ($constants->{clampe_stats} && $user->{uid} > 827000 && $user->{uid} < 832000) { - my $fname = catfile('clampe', $user->{uid}); - my $comlog = "URL: $ENV{REQUEST_URI} IPID: $user->{ipid} UID: $user->{uid} Dispmode: $user->{mode} Thresh: $user->{threshold} Karma: $user->{karma}"; - doClampeLog($fname, [$comlog]); - } - return OK; } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 382] CVS update: slashjp/Slash/Apache/TemplatePages Message-ID: <20060712114137.1A04B2AC011@users.sourceforge.jp> Index: slashjp/Slash/Apache/TemplatePages/TemplatePages.pm diff -u slashjp/Slash/Apache/TemplatePages/TemplatePages.pm:1.3 slashjp/Slash/Apache/TemplatePages/TemplatePages.pm:1.4 --- slashjp/Slash/Apache/TemplatePages/TemplatePages.pm:1.3 Fri Dec 31 21:35:43 2004 +++ slashjp/Slash/Apache/TemplatePages/TemplatePages.pm Wed Jul 12 20:41:36 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: TemplatePages.pm,v 1.3 2004/12/31 12:35:43 oliver Exp $ +# $Id: TemplatePages.pm,v 1.4 2006/07/12 11:41:36 sugi Exp $ package Slash::Apache::TemplatePages; @@ -11,7 +11,7 @@ use Apache::Constants qw(:common); use vars qw($VERSION); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # AMY: Leela's gonna kill me. # BENDER: Naw, she'll probably have me do it. From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 383] CVS update: slashjp/Slash/Apache/User Message-ID: <20060712114137.3BA752AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Apache/User/User.pm diff -u slashjp/Slash/Apache/User/User.pm:1.4 slashjp/Slash/Apache/User/User.pm:1.5 --- slashjp/Slash/Apache/User/User.pm:1.4 Fri Dec 31 21:35:44 2004 +++ slashjp/Slash/Apache/User/User.pm Wed Jul 12 20:41:37 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: User.pm,v 1.4 2004/12/31 12:35:44 oliver Exp $ +# $Id: User.pm,v 1.5 2006/07/12 11:41:37 sugi Exp $ package Slash::Apache::User; @@ -24,7 +24,7 @@ @ISA = qw(DynaLoader); $VERSION = '2.003000'; # v2.3.0 -($REVISION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; +($REVISION) = ' $Revision: 1.5 $ ' =~ /\$Revision:\s+([^\s]+)/; bootstrap Slash::Apache::User $VERSION; @@ -52,6 +52,13 @@ return DECLINED unless $r->is_main; + my $uri = $r->uri; + + # Exclude any URL that matches the environment variable regex + if ($ENV{SLASH_EXCLUDE_URL_USERHANDLER}) { + return OK if $uri =~ /$ENV{SLASH_EXCLUDE_URL_USERHANDLER}/; + } + $request_start_time ||= Time::HiRes::time; # Ok, this will make it so that we can reliably use Apache->request @@ -64,11 +71,21 @@ my $apr = Apache::Request->new($r); my $gSkin = getCurrentSkin(); - $r->header_out('X-Powered-By' => "Slash $Slash::VERSION"); - random($r); + my $reader_user = $slashdb->getDB('reader'); + my $reader = getObject('Slash::DB', { virtual_user => $reader_user }); + + my $version_code = "Slash"; + $version_code .= " $Slash::VERSION"; + if ($constants->{cvs_tag_currentcode_emit} + && $constants->{cvs_tag_currentcode} + && $constants->{cvs_tag_currentcode} =~ /_(\d+)$/) { + $version_code .= sprintf("%03d", $1); + } + $r->header_out('X-Powered-By' => $version_code); + + add_random_quote($r); # let pass unless / or .pl - my $uri = $r->uri; if ($gSkin->{rootdir}) { my $path = URI->new($gSkin->{rootdir})->path; $uri =~ s/^\Q$path//; @@ -77,6 +94,7 @@ my $is_ssl = Slash::Apache::ConnectionIsSSL(); $slashdb->sqlConnect; + $reader->sqlConnect; ################################################## # Don't remove this. This solves a known bug in Apache -- brian @@ -129,7 +147,8 @@ # want to save one bit of information there, and retrieve it # later -- pudge my $user_temp = getCurrentUser(); - $user_temp->{state}{login_temp} = 'no'; + $user_temp->{state}{login_public} = 'no'; + $user_temp->{state}{login_temp} = 'no'; $user_temp->{state}{login_failed_reason} = 0; if ((($op eq 'userlogin' || $form->{rlogin}) && length($form->{upasswd}) > 1) @@ -147,21 +166,18 @@ $logtoken = $form->{logtoken}; } - # Don't allow login attempts from IPIDs that have been marked - # as "nopost" -- those are mostly open proxies. Check both - # the ipid and the subnetid (we can't use values in $user - # because that doesn't get set up until prepareUser is called, - # later in this function). Note we don't have to MD5 the - # values, checkReadOnly() knows how to do that. + # Don't allow login attempts from IPIDs that have been + # marked as "nopost" or "nopostanon" -- those are mostly + # open proxies. Check both the ipid and the subnetid (we + # can't use values in $user because that doesn't get set + # up until prepareUser is called, later in this function). + # XXXSRCID: really should have a separate 'openproxy' + # attribute instead of piggybacking off 'nopost'. my $read_only = 0; my $hostip = $r->connection->remote_ip; - my($ip, $subnet) = get_ipids($hostip, 1); - if ($slashdb->checkReadOnly('nopost', { ipid => $ip })) { - $read_only = 1; - } else { - $read_only = 1 if $slashdb->checkReadOnly('nopost', { - subnetid => $subnet }); - } + my $srcids = get_srcids({ ip => $hostip }); + $read_only = 1 if $reader->checkAL2($srcids, 'nopost') + || $reader->checkAL2($srcids, 'nopostanon'); my $newpass; if ($read_only || !$tmpuid) { @@ -222,13 +238,26 @@ # only allow this for certain pages/ops etc. # and that page must doublecheck for permissions etc., still, # redirecting user back to a main page upon failure + # ... it would be nice to have a way to set this in a table + # or vars or somesuch, but how? is there danger in + # opening it up to everything instead of closing it off? + # NOTE: this is only for "public" logtokens that are + # separate from regular login logtokens right now; + # it can be changed if necessary, it just happens that + # way, so we use it to set login_public if ( - ($constants->{rss_allow_index} && $form->{content_type} eq 'rss' && $uri =~ m{^/index\.pl$}) + ($constants->{rss_allow_index} && $form->{content_type} =~ $constants->{feed_types} && $uri =~ m{^/index\.pl$}) + || + ($constants->{plugin}{ScheduleShifts} && $uri =~ m{^/shifts\.pl$}) || # hmmm ... journal.pl no work, because can be called as /journal/ - ($constants->{journal_rdfitemdesc_html} && $form->{content_type} eq 'rss' && $uri =~ m{\bjournal\b}) + ($constants->{journal_rdfitemdesc_html} + && $form->{content_type} =~ $constants->{feed_types} + && $uri =~ m{\b(?:journal|messages|inbox)\b} + ) ) { $logtoken = $form->{logtoken}; + $user_temp->{state}{login_public} = 'yes'; } else { delete $form->{logtoken}; } @@ -237,51 +266,50 @@ my($tmpuid, $value) = eatUserCookie($logtoken || ($cookies->{user} && $cookies->{user}->value)); my $cookvalue; if ($tmpuid && $tmpuid > 0 && $tmpuid != $constants->{anonymous_coward_uid}) { + my $kind = $user_temp->{state}{login_public} eq 'yes' ? 4 : 0; ($uid, $cookvalue) = - $slashdb->getUserAuthenticate($tmpuid, $value, 0, 1); + $slashdb->getUserAuthenticate($tmpuid, $value, $kind, 1); } # we don't want to set a cookie etc. if user is using a $logtoken, # as that is just for RSS etc. - if (!$logtoken && $uid && $op ne 'userclose') { - # set cookie every time, in case session_login - # value changes, or time is almost expired on - # saved cookie, or password changes, or ... - - # can't set it every time, it upsets people. - # we need to set it only if password or - # session_login changes. -- pudge - - # if existing cookie is not a logtoken cookie, make it one - if ($value !~ m|^[A-Za-z0-9/+]{22}$|) { - setCookie('user', bakeUserCookie($uid, $cookvalue), - $slashdb->getUser($uid, 'session_login') - ); - - # always set cookie for "temp" logins, on every request - } elsif ($user_temp->{state}{login_temp} eq 'yes') { - setCookie('user', bakeUserCookie($uid, $cookvalue), 2); - } - - # blank out user cookie and make anon if user wants to log out, or - # uses a bad cookie - } elsif (!$logtoken && dbAvailable()) { - if ($op eq 'userclose') { - $slashdb->deleteLogToken($uid); - } + if (!$logtoken) { + if ($uid && $op ne 'userclose') { + # set cookie every time, in case session_login + # value changes, or time is almost expired on + # saved cookie, or password changes, or ... + + # can't set it every time, it upsets people. + # we need to set it only if password or + # session_login changes. -- pudge + + # if existing cookie is not a logtoken cookie, make it one + if ($value !~ m|^[A-Za-z0-9/+]{22}$|) { + setCookie('user', bakeUserCookie($uid, $cookvalue), + $slashdb->getUser($uid, 'session_login') + ); + + # always set cookie for "temp" logins, on every request + } elsif ($user_temp->{state}{login_temp} eq 'yes') { + setCookie('user', bakeUserCookie($uid, $cookvalue), 2); + } + + # blank out user cookie and make anon if user wants + # to log out, or uses a bad cookie + } elsif (dbAvailable()) { + if ($op eq 'userclose' && $uid) { + $slashdb->deleteLogToken($uid); + } - $uid = $constants->{anonymous_coward_uid}; - delete $cookies->{user}; - # if you are here, chances are your cookie is bad, - # so we blank it out for you. you're welcome. - setCookie('user', ''); + $uid = $constants->{anonymous_coward_uid}; + delete $cookies->{user}; + # if you are here, chances are your cookie is bad, + # so we blank it out for you. you're welcome. + setCookie('user', ''); + } } } elsif ($op eq 'userclose') { - # When did we comment out this? This means that even - # if an author logs out, the other authors will - # not know about it. Bad.... - #$slashdb->deleteSession(); # if $slashdb->getUser($uid, 'seclev') >= 99; delete $cookies->{user}; setCookie('user', ''); } @@ -324,7 +352,7 @@ $srand_called ||= 1; # If this uid is marked as banned, deny them access. - my $banlist = $slashdb->getBanList(); + my $banlist = $reader->getBanList; if ($banlist->{$uid}) { # The global current user hasn't been created yet, so the # template expects uid just passed in as the var named "uid". @@ -332,7 +360,7 @@ slashDisplay('bannedtext_uid', { uid => $uid }, { Return => 1 } ) ); # Now we need to create a user hashref for that global - # current user, so the "uid" field of accesslog gets written + # current user, so these fields of accesslog get written # correctly when we log this attempted hit. We do this # dummy hashref with the bare minimum of values that we need, # instead of going through prepareUser(), because this is @@ -354,12 +382,20 @@ if ($uri =~ /\.pl$/ || $uri =~ /\.tmpl$/) { $user->{state}{_dynamic_page} = 1; } - $user->{state}{login_temp} = $user_temp->{state}{login_temp}; + $user->{state}{login_public} = $user_temp->{state}{login_public}; + $user->{state}{login_temp} = $user_temp->{state}{login_temp}; $user->{state}{login_failed_reason} = $user_temp->{state}{login_failed_reason}; $user->{state}{ssl} = $is_ssl; createCurrentUser($user); createCurrentForm($form); + if ($gSkin->{require_acl} && !$user->{acl}{$gSkin->{require_acl}}) { + $r->err_header_out(Location => + URI->new_abs('/', $constants->{absolutedir}) + ); + return REDIRECT; + } + # If the user is connecting over SSL, make sure this is allowed. # If allow_nonadmin_ssl is 0, then only admins are allowed in. # If allow_nonadmin_ssl is 1, then anyone is allowed in. @@ -417,7 +453,7 @@ createCurrentCookie($cookies); createEnv($r) if $cfg->{env}; - authors($r) if $form->{'slashcode_authors'}; + add_author_quotes($r) if $form->{slashcode_authors}; # a special test mode for getting a new template # object (hence, fresh cache) for each request @@ -457,15 +493,15 @@ } ######################################################## -# These are very import, do not delete these -sub random { +# These are very important, do not delete these +sub add_random_quote { my($r) = @_; my $quote = $QUOTES[int(rand(@QUOTES))]; (my($who), $quote) = split(/: */, $quote, 2); $r->header_out("X-$who" => $quote); } -sub authors { +sub add_author_quotes { my($r) = @_; $r->header_out('X-Author-Krow' => "You can't grep a dead tree."); $r->header_out('X-Author-Pudge' => "Bite me."); @@ -477,6 +513,7 @@ sub userLogin { my($uid_try, $passwd, $logtoken) = @_; my $slashdb = getCurrentDB(); + my($user) = getCurrentUser(); # only allow plain text passwords, unless logtoken is passed, # then only allow that @@ -490,7 +527,10 @@ if (!isAnon($uid)) { setCookie('user', bakeUserCookie($uid, $cookvalue), - $slashdb->getUser($uid, 'session_login')); + $user->{state}{login_temp} eq 'yes' + ? 2 + : $slashdb->getUser($uid, 'session_login') + ); return($uid, $newpass); } else { my $gSkin = getCurrentSkin(); @@ -501,6 +541,10 @@ } ######################################################## +# XXX May want to rename this, since it's being used for a user's +# prefs/info pages (/my/foo) and for the global handlers too (/foo). +# Of course renaming requires editing a .conf file (see +# bin/install-slashsite PerlTransHandler). sub userdir_handler { my($r) = @_; @@ -516,6 +560,12 @@ $uri =~ s/^\S+\s+//; $uri =~ s/\s+\S+$//; $uri =~ s/\+/ /g; + + my $logtoken; + if ($uri =~ s{(?:^|/)?(\d+(?::|%3[aA]){2}\w+)$}{}) { + $logtoken = $1; + } + my $saveuri = $uri; $uri =~ s/%([a-fA-F0-9]{2})/pack('C', hex($1))/ge; @@ -524,103 +574,156 @@ $uri =~ s/^\Q$path//; } + # URIs like /tags and /tags/foo and /tags/foo?type=bar are special cases. + if ($uri =~ m[^/tags (?: /([^?]*) | /? ) (?: \?(.*) )? $]x) { + my($word, $query) = ($1, $2); + my @args = ( ); + if ($word =~ /^(active|recent|all)$/) { + push @args, "type=$word"; + } else { + push @args, "tagname=$word"; + } + push @args, $query if defined $query; + $r->args(join('&', @args)); + $r->uri('/tags.pl'); + $r->filename($constants->{basedir} . '/tags.pl'); + return OK; + } + # for self-references (/~/ and /my/) if (($saveuri =~ m[^/(?:%7[eE]|~)] && $uri =~ m[^/~ (?: /(.*) | /? ) $]x) # /my/ or /my can match, but not /mything - or ($uri =~ m[^/my (?: /(.*) | /? ) $]x) + || $uri =~ m[^/my (?: /(.*) | /? ) $]x ) { - my $match = $1; - if ($r->header_in('Cookie') =~ $USER_MATCH) { - my($op, $extra) = split /\//, $match, 2; - if ($op eq 'journal') { - my $args; - if ($extra && $extra =~ /^\d+$/) { - $args = "id=$extra&op=edit"; - } elsif ($extra && $extra eq 'friends') { - $args = "op=friendview"; - } else { - $args = "op=list"; + my($string, $query) = ($1, ''); + if ($string =~ s/\?(.+)$//) { + # This seems to have no effect, right? since $query + # is redeclared in a different scope below -Jamie + # This is in case something in this scope wants it -- pudge + $query = $1; + } + + my($op, $extra) = split /\//, $string, 2; + + my $logged_in = $r->header_in('Cookie') =~ $USER_MATCH; + my $try_login = !$logged_in && $logtoken; + + my $found_the_op = 0; + if ($logged_in || $try_login) { + if ($op eq 'inbox') { + $found_the_op = 1; + my $args = 'op=list'; + if ($extra =~ m{^ (rss|atom) /? $}x) { + $args .= '_rss'; + $args .= "&logtoken=$logtoken" if $try_login; + $args .= "&content_type=$1"; } + $r->args($args); - $r->uri('/journal.pl'); - $r->filename($constants->{basedir} . '/journal.pl'); - } elsif ($op eq 'discussions') { - $r->args("op=personal_index"); - $r->uri('/comments.pl'); - $r->filename($constants->{basedir} . '/comments.pl'); - } elsif ($op eq 'inbox') { - $r->args("op=list"); - $r->uri('/messages.pl'); - $r->filename($constants->{basedir} . '/messages.pl'); - } elsif ($op eq 'messages') { # XXX change to be same as /inbox, move this to /my/preferences/messages - $r->args("op=display_prefs"); $r->uri('/messages.pl'); $r->filename($constants->{basedir} . '/messages.pl'); - } elsif ($op eq 'friends') { - if ($extra eq 'friends') { - $r->args("op=fof"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } elsif ($extra eq 'foes') { - $r->args("op=eof"); + } elsif ($logged_in) { + $found_the_op = 1; + if ($op eq 'journal') { + my $args; + if ($extra && $extra =~ /^\d+$/) { + $args = "id=$extra&op=edit"; + } elsif ($extra && $extra eq 'friends') { + $args = "op=friendview"; + } else { + $args = "op=list"; + } + $r->args($args); + $r->uri('/journal.pl'); + $r->filename($constants->{basedir} . '/journal.pl'); + + } elsif ($op eq 'discussions') { + $r->args("op=personal_index"); + $r->uri('/comments.pl'); + $r->filename($constants->{basedir} . '/comments.pl'); + + + } elsif ($op eq 'messages') { # XXX change to be same as /inbox, move this to /my/preferences/messages + $r->args("op=display_prefs"); + $r->uri('/messages.pl'); + $r->filename($constants->{basedir} . '/messages.pl'); + + } elsif ($op =~ /^(?:friends|fans|freaks|foes|zoo)$/) { + my $args = "op=$op"; + $extra .= '/'; + + if ($op eq 'friends' && $extra =~ s/^friends\///) { + $args =~ s/friends/fof/; + } elsif ($op eq 'friends' && $extra =~ s/^foes\///) { + $args =~ s/friends/eof/; + } elsif ($op eq 'zoo') { + $args =~ s/zoo/all/; + } + + $r->args($args); $r->uri('/zoo.pl'); $r->filename($constants->{basedir} . '/zoo.pl'); + + } elsif ($op eq 'comments') { + $r->args("op=editcomm"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); + + } elsif ($op eq 'homepage') { + $r->args("op=edithome"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); + + } elsif ($op eq 'password') { + $r->args("op=changeprefs"); + $r->uri('/login.pl'); + $r->filename($constants->{basedir} . '/login.pl'); + + } elsif ($op eq 'logout') { + $r->args("op=userclose"); + $r->uri('/login.pl'); + $r->filename($constants->{basedir} . '/login.pl'); + + } elsif ($op eq 'misc') { + $r->args("op=editmiscopts"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); + + } elsif ($op eq 'amigos') { + $r->args("op=friendview"); + $r->uri('/journal.pl'); + $r->filename($constants->{basedir} . '/journal.pl'); + + } elsif ($op eq 'tags') { + $r->args("op=showtags"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); + + } elsif ($op eq 'bookmarks') { + $r->args("op=showbookmarks"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); + } else { - $r->args("op=friends"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); + $r->args("op=edituser"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); } - } elsif ($op eq 'foes') { - $r->args("op=foes"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } elsif ($op eq 'fans') { - $r->args("op=fans"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } elsif ($op eq 'freaks') { - $r->args("op=freaks"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } elsif ($op eq 'zoo') { - $r->args("op=all"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } elsif ($op eq 'comments') { - $r->args("op=editcomm"); - $r->uri('/users.pl'); - $r->filename($constants->{basedir} . '/users.pl'); - } elsif ($op eq 'homepage') { - $r->args("op=edithome"); - $r->uri('/users.pl'); - $r->filename($constants->{basedir} . '/users.pl'); - } elsif ($op eq 'password') { - $r->args("op=changeprefs"); - $r->uri('/login.pl'); - $r->filename($constants->{basedir} . '/login.pl'); - } elsif ($op eq 'logout') { - $r->args("op=userclose"); - $r->uri('/login.pl'); - $r->filename($constants->{basedir} . '/login.pl'); - } elsif ($op eq 'misc') { - $r->args("op=editmiscopts"); - $r->uri('/users.pl'); - $r->filename($constants->{basedir} . '/users.pl'); - } elsif ($op eq 'amigos') { - $r->args("op=friendview"); - $r->uri('/journal.pl'); - $r->filename($constants->{basedir} . '/journal.pl'); - } else { - $r->args("op=edituser"); - $r->uri('/users.pl'); - $r->filename($constants->{basedir} . '/users.pl'); } - return OK; - } else { + + } + if (!$found_the_op) { $r->uri('/login.pl'); $r->filename($constants->{basedir} . '/login.pl'); - return OK; } + + return OK; + + } elsif ($uri =~ m[^/bookmarks (?: /(.*) | /? ) $]x) { + $r->args('op=showbookmarks'); + $r->uri('/bookmark.pl'); + $r->filename($constants->{basedir} . '/bookmark.pl'); + return OK; } # assuming Apache/mod_perl is decoding the URL in ->uri before @@ -638,7 +741,9 @@ } my $slashdb = getCurrentDB(); - my $uid = $slashdb->getUserUID($nick); + my $reader_user = $slashdb->getDB('reader'); + my $reader = getObject('Slash::DB', { virtual_user => $reader_user }); + my $uid = $reader->getUserUID($nick); $nick = fixparam($nick); # make safe to pass back to script # maybe we should refactor this code a bit ... @@ -664,12 +769,9 @@ if ($extra =~ s/^friends\///) { $args =~ s/display/friendview/; } - if ($extra =~ /^rss(\/(\d+::\w+)?)?$/) { - if ($2) { - (my $logtoken = $2) =~ s/::/%3A%3A/; - $args .= "&logtoken=$logtoken"; - } - $args .= "&content_type=rss"; + if ($extra =~ m{^ (rss|atom) / ? $}x) { + $args .= "&logtoken=$logtoken" if $logtoken; + $args .= "&content_type=$1"; } } $args .= "&$query"; @@ -697,42 +799,23 @@ $r->uri('/users.pl'); $r->filename($constants->{basedir} . '/users.pl'); - } elsif ($op eq 'friends') { - if ($extra eq 'friends') { - $r->args("op=fof&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } elsif ($extra eq 'foes') { - $r->args("op=eof&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } else { - $r->args("op=friends&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - } - } elsif ($op eq 'friends.rdf') { - $r->args("op=friends&nick=$nick&uid=$uid&content_type=foaf"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); - - } elsif ($op eq 'fans') { - $r->args("op=fans&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); + } elsif ($op =~ /^(?:friends|fans|freaks|foes|zoo)$/) { + my $args = "op=$op&nick=$nick&uid=$uid"; + $extra .= '/' . $more; - } elsif ($op eq 'freaks') { - $r->args("op=freaks&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); + if ($op eq 'friends' && $extra =~ s/^friends\///) { + $args =~ s/friends/fof/; + } elsif ($op eq 'friends' && $extra =~ s/^foes\///) { + $args =~ s/friends/eof/; + } elsif ($op eq 'zoo') { + $args =~ s/zoo/all/; + } - } elsif ($op eq 'foes') { - $r->args("op=foes&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); + if ($extra =~ m{^ (rss|atom) /?$}x) { + $args .= "&content_type=$1"; + } - } elsif ($op eq 'foes.rdf') { - $r->args("op=foes&nick=$nick&uid=$uid&content_type=foaf"); + $r->args($args); $r->uri('/zoo.pl'); $r->filename($constants->{basedir} . '/zoo.pl'); @@ -741,10 +824,15 @@ $r->uri('/journal.pl'); $r->filename($constants->{basedir} . '/journal.pl'); - } elsif ($op eq 'foaf.rdf') { - $r->args("op=foaf&nick=$nick&uid=$uid"); - $r->uri('/zoo.pl'); - $r->filename($constants->{basedir} . '/zoo.pl'); + } elsif ($op eq 'tags') { + $r->args("op=showtags&nick=$nick&uid=$uid"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); + + } elsif ($op eq 'bookmarks') { + $r->args("op=showbookmarks&nick=$nick&uid=$uid"); + $r->uri('/users.pl'); + $r->filename($constants->{basedir} . '/users.pl'); } else { $r->args("nick=$nick&uid=$uid"); @@ -811,6 +899,8 @@ Bender:Boy, who knew a cooler could also make a handy wang coffin? Bender:I'm so embarrassed. I wish everybody else was dead. Bender:Professor! Make a woman out of me! +Bender:Would we have donkeys? +Bender:Emotions are dumb and should be hated. Bender:An upgrade? I thought we all agreed I was perfect. Bender:Curse you, merciful Poseidon! Bender:I am a hideous triumph of form and function. @@ -826,9 +916,20 @@ Bender:I choose to not understand these signs! Bender:Aw, this bends! Bender:Farewell, big blue ball of idiots! -Bender:This guy's not making any sense. Can I kill him? Please? +Bender:This guy's not making any sense. Can I kill him? Please? Bender:Hooray, we don't have to do anything! Bender:I only speak enough binary to ask where the bathroom is. +Bender:nogoodlawsprotectingtheinnocent-- +Bender:Senseless death! The folk singer's best friend! +Bender:Alright! Closure! +Bender:You just lost five dollars. +Bender:That's not my gold-plated 25-pin connector. +Bender:I only know enough binary to ask where the bathroom is. +Bender:Why would God think in binary? +Bender:You can't count on God for jack! He pretty much told me so himself. +Bender:Stop doing the right thing, you jerk! +Bender:Are you familiar with the old robot saying "does not compute"? +Bender:The sparks keep me warm. Fry:There's a lot about my face you don't know. Fry:These new hands are great. I'm gonna break them in tonight. Fry:I refuse to testify on the grounds that my organs will be chopped up into a patty. @@ -838,6 +939,7 @@ Fry:People said I was dumb but I proved them! Fry:It's like a party in my mouth and everyone's throwing up. Fry:I don't regret this, but I both rue and lament it. +Fry:You'll barely regret this. Fry:I'm never gonna get used to the thirty-first century. Caffeinated bacon? Fry:They're great! They're like sex except I'm having them. Fry:No, no, I was just picking my nose. @@ -860,9 +962,28 @@ Fry:The butter in my pocket is melting! Fry:Stop abducting me! Fry:What kind of bozos would start a Bender protest group? -Fry:I can burp the alphabet. A, B, D ... no, wait ... +Fry:I can burp the alphabet. A, B, D ... no, wait ... Fry:Why use my own legs like an idiot when I can use a Chickenwalker? Fry:Hooray, we don't have to do anything! +Fry:Prepare to be thought at! +Fry:I did it! And it's all thanks to the books at my local library. +Fry:Existing is basically all I do! +Fry:It's a widely-believed fact! +Fry:My hands! My horrible, human hands! +Fry:How about me? I'm human, and I've always wanted to see the future! +Fry:The less fortunate get all the breaks! +Fry:Please, Mr. Nixon! We're appealing to your sense of decency! +Fry:I have more important things to do today than laugh and clap my hands. +Fry:I'll be whatever I wanna do. +Fry:There's a political debate on. Quick, change the channel! +Leela:There's a political debate on. Quick, change the channel! +Leela:You did the best you could, I guess, and some of these gorillas are okay. +Leela:This wangs chung. +Leela:This toads the wet sprocket. +Leela:He opened up relations with China. He doesn't want to hear about your ding-dong. +Leela:This is by a wide margin the least likely thing that has ever happened. +Leela:I'm a millionaire! Suddenly I have an opinion about the capital gains tax. +Leela:Do you have idiots on your planet? EOT 1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 384] CVS update: slashjp/Slash/Client Message-ID: <20060712114137.61AC82AC011@users.sourceforge.jp> Index: slashjp/Slash/Client/.cvsignore diff -u /dev/null slashjp/Slash/Client/.cvsignore:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/.cvsignore Wed Jul 12 20:41:37 2006 @@ -0,0 +1,2 @@ +Slash-Client-* +.lwpcookies Index: slashjp/Slash/Client/.releaserc diff -u /dev/null slashjp/Slash/Client/.releaserc:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/.releaserc Wed Jul 12 20:41:37 2006 @@ -0,0 +1,6 @@ +cpan_user=CNANDOR +sf_user=pudge +sf_group_id=4421 +sf_package_id=170031 +sf_release_match=^.+-([\d.]+)$ +sf_release_replace=$1 Index: slashjp/Slash/Client/MANIFEST diff -u /dev/null slashjp/Slash/Client/MANIFEST:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/MANIFEST Wed Jul 12 20:41:37 2006 @@ -0,0 +1,7 @@ +lib/Slash/Client.pm +lib/Slash/Client/Journal.pm +Makefile.PL +MANIFEST +README +t/journal.t +t/pod.t Index: slashjp/Slash/Client/Makefile.PL diff -u /dev/null slashjp/Slash/Client/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/Makefile.PL Wed Jul 12 20:41:37 2006 @@ -0,0 +1,13 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + 'NAME' => 'Slash::Client', + 'VERSION_FROM' => 'lib/Slash/Client.pm', + 'clean' => { + 'FILES' => 'Slash-Client-*' + }, + 'NO_META' => 1, + 'PREREQ_PM' => { + 'SOAP::Lite' => 0, + }, +); Index: slashjp/Slash/Client/README diff -u /dev/null slashjp/Slash/Client/README:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/README Wed Jul 12 20:41:37 2006 @@ -0,0 +1,4 @@ +# $Id: README,v 1.1 2006/07/12 11:41:37 sugi Exp $ + +This is an API for writing Slash clients. Read the POD for more information. +Right now, it is only useful for writing SOAP clients for Slash journals. From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 385] CVS update: slashjp/Slash/Client/lib/Slash Message-ID: <20060712114137.80BE02AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Client/lib/Slash/Client.pm diff -u /dev/null slashjp/Slash/Client/lib/Slash/Client.pm:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/lib/Slash/Client.pm Wed Jul 12 20:41:37 2006 @@ -0,0 +1,207 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: Client.pm,v 1.1 2006/07/12 11:41:37 sugi Exp $ + +package Slash::Client; + +use strict; +use warnings; + +use Digest::MD5 'md5_hex'; +use File::Spec::Functions; + +our $VERSION = 0.01; + +sub new { + my($class, $opts) = @_; + + my $self = {}; + $self->{host} = $opts->{host} or return; + $self->{http} = $opts->{ssl} ? 'https' : 'http'; + + $self->{uid} = $opts->{uid}; + $self->{pass} = $opts->{pass}; + $self->{logtoken} = $opts->{logtoken}; + $self->{cookie_file} = $opts->{cookie_file}; + + bless $self, $class; + return $self; +} + +sub soap { + my($self) = @_; + my $uri = $self->{soap}{uri} or return; + my $proxy = $self->{soap}{proxy} or return; + + return $self->{soap}{cache} if $self->{soap}{cache}; + + require HTTP::Cookies; + require SOAP::Lite; + + my $cookies = HTTP::Cookies->new; + + if ($self->{logtoken}) { + $cookies->set_cookie(0, user => $self->{logtoken}, '/', $self->{host}); + + } elsif ($self->{uid} && $self->{pass}) { + my $cookie = bakeUserCookie($self->{uid}, $self->{pass}); + $cookies->set_cookie(0, user => $cookie, '/', $self->{host}); + + } else { + my $cookie_file = $self->{cookie_file} || find_cookie_file(); + if ($cookie_file) { + $cookies = HTTP::Cookies::Netscape->new; + $cookies->load($cookie_file); + } + } + + my $soap = SOAP::Lite->uri($uri)->proxy($proxy, cookie_jar => $cookies); + $self->{soap}{cache} = $soap; + return $soap; +} + + +sub find_cookie_file { + my $app = shift || 'Firefox'; + my $file; + if ($^O eq 'MacOS' || $^O eq 'darwin') { + require Mac::Files; + Mac::Files->import(':DEFAULT'); + + my($dir, $vref, $type); + if ($^O eq 'darwin') { + $vref = &kUserDomain; + if ($app eq 'Chimera' || $app eq 'Firefox') { + $type = &kApplicationSupportFolderType; + } elsif ($app eq 'Mozilla') { + $type = &kDomainLibraryFolderType; + } + } elsif ($^O eq 'MacOS') { + $vref = &kOnSystemDisk; + $type = &kDocumentsFolderType; + } + + $dir = FindFolder($vref, $type, &kDontCreateFolder); + $dir = catdir($dir, $app, 'Profiles'); + for (0, 1) { + last if -e catfile($dir, 'cookies.txt'); + opendir(my $dh, $dir) or die "Can't open $dir: $!"; + $dir = catdir($dir, (grep !/^\./, readdir($dh))[0]); + closedir($dh); + } + $file = catfile($dir, 'cookies.txt'); + } + return $file; +} + +sub bakeUserCookie { + my($uid, $pass) = @_; + my $cookie = $uid . '::' . md5_hex($pass); + $cookie =~ s/(.)/sprintf("%%%02x", ord($1))/ge; + $cookie =~ s/%/%25/g; + return $cookie; +} + +sub literal { + my($str) = @_; + $str =~ s/&/&/g; + $str =~ s//>/og; + return $str; +} + +sub fixparam { + my($str) = @_; + $str =~ s/([^$URI::unreserved ])/$URI::Escape::escapes{$1}/og; + $str =~ s/ /+/g; + return $str; +} + +1; + +__END__ + +=head1 NAME + +Slash::Client - Write clients for Slash + +=head1 SYNOPSIS + + my $client = Slash::Client::Journal->new({ + host => 'use.perl.org', + }); + my $entry = $client->get_entry(10_000); + +=head1 DESCRIPTION + +Slash::Client allows writing clients to access Slash. So far, only one +client is implemented: accessing journals, which is done via SOAP. See +L for more information. + +=head2 Constructor + +You create an object with the C constructor, which takes a hashref +of options. + +=over 4 + +=item host + +The Slash site's host name. + +=item ssl + +Boolean, true if the Slash site can be accessed via SSL. + +=item uid + +=item pass + +If uid and pass have true values, they are used to construct the cookie +for authentication purposes. See L. + +=item logtoken + +Logtoken is used for the cookie if it is passed. + +=item cookie_file + +Path to the file in Netscape format containing a cookie. + +=back + +=head2 Authentication + +Some methods require authentication; others may require authentication, +depending on the site. + +There are three ways to authenticate. The first that's tried is uid/pass. +If those are not supplied, logtoken is used: this is the value actually +stored in the browser cookie (and used in the query string for some +user-authenticated feed URLS). The third is to just try to load the cookie +from a cookie file, either passing in a path in cookie_file, or trying to +find the file automatically. + +I've only tested the cookie authentication recently with Firefox on Mac OS X. +Feel free to submit patches for other browsers and platforms. + +If the given authentication method fails, others are not attempted, and the +method will attempt to execute anyway. + + +=head1 TODO + +Work on error handling. + +Other platforms for finding/reading cookies. + + +=head1 SEE ALSO + +Slash::Client::Journal(3). + + +=head1 VERSION + +$Id: Client.pm,v 1.1 2006/07/12 11:41:37 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 386] CVS update: slashjp/Slash/Client/lib/Slash/Client Message-ID: <20060712114137.A74E02AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Client/lib/Slash/Client/Journal.pm diff -u /dev/null slashjp/Slash/Client/lib/Slash/Client/Journal.pm:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/lib/Slash/Client/Journal.pm Wed Jul 12 20:41:37 2006 @@ -0,0 +1,189 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: Journal.pm,v 1.1 2006/07/12 11:41:37 sugi Exp $ + +package Slash::Client::Journal; + +use strict; +use warnings; + +use base 'Slash::Client'; + +our $VERSION = 0.01; + +sub new { + my($class, $opts) = @_; + + my $self = $class->SUPER::new($opts); + $self->{soap}{uri} = "$self->{http}://$self->{host}/Slash/Journal/SOAP"; + $self->{soap}{proxy} = "$self->{http}://$self->{host}/journal.pl"; + + return $self; +} + +sub _return_from_entry { + my($self, $id, $list) = @_; + + if ($list) { + my $entry = $self->get_entry($id); + return($id, $entry->{url}) if $entry && $entry->{url}; + } else { + return $id; + } + + return; +} + +sub add_entry { + my($self, $data) = @_; + + $data->{body} =~ s/\n/\012/g; # Local to Unix newlines, JIC + + my $id = 0; + if ($data->{subject} && $data->{body}) { + $id = $self->soap->add_entry($data)->result; + } + + return $self->_return_from_entry($id, wantarray()); +} + +sub modify_entry { + my($self, $id, $data) = @_; + + $data->{body} =~ s/\n/\012/g; # Local to Unix newlines, JIC + + my $newid = 0; + if ($data->{subject} && $data->{body} && $id) { + $newid = $self->soap->modify_entry($id, $data)->result; + } + + return $self->_return_from_entry($id, wantarray()); +} + +sub delete_entry { + my($self, $id) = @_; + + return $self->soap->delete_entry($id)->result; +} + +sub get_entry { + my($self, $id) = @_; + + return $self->soap->get_entry($id)->result; +} + +sub get_entries { + my($self, $uid, $limit) = @_; + + return $self->soap->get_entries($uid, $limit)->result; +} + +1; + +# http://use.perl.org/~pudge/journal/3294 + +__END__ + +=head1 NAME + +Slash::Client::Journal - Write journal clients for Slash + +=head1 SYNOPSIS + + my $client = Slash::Client::Journal->new({ + host => 'use.perl.org', + }); + my $entry = $client->get_entry(10_000); + +=head1 DESCRIPTION + +Slash::Client::Journal provides an API for writing clients for Slash journals. + +See L for details on authentication and for more information. + +=head2 Methods + +=over 4 + +=item add_entry(HASHREF) + +Add an entry. Must be authenticated. + +Pass key-value pairs for C and C (both required). Other optional +keys are C, C, and C. + +C is a boolean for turning on discussions. If false, comments +are not turned on. If true, the user's prefs on the site are used (which +is also the default). + +C is an integer defining the post types. This is subject to change, +but is currently: 1 = Plain Old Text, 2 = HTML Formatted, +3 = Extrans (html tags to text), 4 = Code. Again, default is to simply use +the user's preferences. + +C is a topic ID. This varies widely between Slash sites. To get a list, +view the source of the journal editing page and look for the "tid" form values. + +In scalar context, returns the unique ID of the new entry, or false if failure. + +In list context, on success, returns the URL to the new journal entry as +the second list element. + + +=item modify_entry(ID, HASHREF) + +Modify an existing entry. Must be authenticated. + +Parameters are just like C. (Note: C cannot be modified +if a discussion had already been created for the entry.) + +In scalar context, returns the unique ID of the modified entry, or false if +failure. + +In list context, on success, returns the URL to the modified journal entry as +the second list element. + + +=item delete_entry(ID) + +Deletes an existing entry. Must be authenticated. + +Returns true on success, false on error. + + +=item get_entries(UID [, LIMIT]) + +Gets the entries for a given user. If LIMIT is not supplied, a site-defined +LIMIT is used. + +Returns an arrayref of hashrefs, where each hashref is an entry, with the keys +being the entry's id, URL, and subject. + +Returns false on error. + + +=item get_entry(ID) + +Get an entry. Returns lots of information about the entry, including uid, +nickname, date, subject, discussion ID, tid, body, URL, id, posttype, +and discussion URL. + +Returns false on error. + +=back + + +=head1 TODO + +Work on error handling. + + +=head1 SEE ALSO + +Slash::Client(3). + + +=head1 VERSION + +$Id: Journal.pm,v 1.1 2006/07/12 11:41:37 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 387] CVS update: slashjp/Slash/Client/t Message-ID: <20060712114137.CF80C2AC011@users.sourceforge.jp> Index: slashjp/Slash/Client/t/journal.t diff -u /dev/null slashjp/Slash/Client/t/journal.t:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/t/journal.t Wed Jul 12 20:41:37 2006 @@ -0,0 +1,40 @@ +#!/usr/bin/perl -w +use Test::More; +use strict; + +BEGIN { + $|++; + plan tests => 10; + use_ok('Slash::Client'); + use_ok('Slash::Client::Journal'); +} + +my $id = 10_000; +my $host = 'use.perl.org'; + +my %checks = ( + id => $id, + discussion_id => 10676, + uid => 44, + nickname => 'brian_d_foy', + subject => '10,000th post', +); + + +my $client = Slash::Client::Journal->new({ + host => $host, + uid => '-', # NOTE: setting uid/pass to bad values ensures + pass => '-' # we don't get logged in, which is what we want, + # to ensure we don't delete anything by accident +}); +ok($client, 'Create object'); + +my $result = $client->get_entry($id); +ok($result, 'Get entry'); + +for (sort keys %checks) { + is($checks{$_}, $result->{$_}, "Check return value for $_"); +} + +ok(!$client->delete_entry($id), "Can't delete, we aren't logged in"); + Index: slashjp/Slash/Client/t/pod.t diff -u /dev/null slashjp/Slash/Client/t/pod.t:1.1 --- /dev/null Wed Jul 12 20:41:37 2006 +++ slashjp/Slash/Client/t/pod.t Wed Jul 12 20:41:37 2006 @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w +use strict; +use Test::More; +use File::Spec; +use File::Find; + +eval "use Test::Pod 0.95"; + +if ($@) { + plan skip_all => "Test::Pod v0.95 required for testing POD"; +} else { + Test::Pod->import; + my @files; + my $blib = File::Spec->catfile(qw(blib lib)); + find( sub {push @files, $File::Find::name if /\.p(l|m|od)$/}, $blib); + plan tests => scalar @files; + foreach my $file (@files) { + pod_file_ok($file); + } +} + +__END__ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:37 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:37 +0900 Subject: [Slashdotjp-dev 388] CVS update: slashjp/Slash/Constants Message-ID: <20060712114137.F0EC82AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Constants/Constants.pm diff -u slashjp/Slash/Constants/Constants.pm:1.2 slashjp/Slash/Constants/Constants.pm:1.3 --- slashjp/Slash/Constants/Constants.pm:1.2 Wed Dec 22 18:13:32 2004 +++ slashjp/Slash/Constants/Constants.pm Wed Jul 12 20:41:37 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Constants.pm,v 1.2 2004/12/22 09:13:32 oliver Exp $ +# $Id: Constants.pm,v 1.3 2006/07/12 11:41:37 sugi Exp $ package Slash::Constants; @@ -29,7 +29,7 @@ use base 'Exporter'; use vars qw(@ISA $VERSION @EXPORT @EXPORT_OK %EXPORT_TAGS %CONSTANTS); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; constants(); @EXPORT = qw(); @@ -111,10 +111,14 @@ MSG_CODE_ZOO_CHANGE MSG_CODE_BADPASSWORD MSG_CODE_MODSTATS + MSG_CODE_SUBSCRIPTION_LOW + MSG_CODE_SUBSCRIPTION_OUT + MSG_CODE_SCHEDULECHG + MSG_CODE_HTML_INVALID =cut -# -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 +# -2 -1 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 =pod @@ -137,6 +141,19 @@ # 0 1 +=head2 reskey + +These constants are used for resource keys. + + RESKEY_NOOP + RESKEY_SUCCESS + RESKEY_FAILURE + RESKEY_DEATH + +=cut + +# -1 0 1 2 + =head2 strip These constants are used to define the modes passed to stripByMode(). Only @@ -199,4 +216,4 @@ =head1 VERSION -$Id: Constants.pm,v 1.2 2004/12/22 09:13:32 oliver Exp $ +$Id: Constants.pm,v 1.3 2006/07/12 11:41:37 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:38 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:38 +0900 Subject: [Slashdotjp-dev 389] CVS update: slashjp/Slash/Custom/ApacheCompress Message-ID: <20060712114138.249442AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Custom/ApacheCompress/ApacheCompress.pm diff -u slashjp/Slash/Custom/ApacheCompress/ApacheCompress.pm:1.1 slashjp/Slash/Custom/ApacheCompress/ApacheCompress.pm:1.2 --- slashjp/Slash/Custom/ApacheCompress/ApacheCompress.pm:1.1 Wed Dec 22 18:13:32 2004 +++ slashjp/Slash/Custom/ApacheCompress/ApacheCompress.pm Wed Jul 12 20:41:37 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ApacheCompress.pm,v 1.1 2004/12/22 09:13:32 oliver Exp $ +# $Id: ApacheCompress.pm,v 1.2 2006/07/12 11:41:37 sugi Exp $ # this merely overrides a "broken" method in Apache::SSI, # where include directives don't work for mixing with Apache::Compress @@ -20,12 +20,13 @@ use Apache::File; use Apache::Constants qw(:common); -($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; sub handler { my $r = shift; + + my $can_gzip = can_gzip($r); - my $can_gzip = $r->header_in('Accept-Encoding') =~ /gzip/; my $filter = lc $r->dir_config('Filter') eq 'on'; #warn "can_gzip=$can_gzip, filter=$filter"; return DECLINED unless $can_gzip or $filter; @@ -33,8 +34,8 @@ # Other people's eyes need to check this 1.1 stuff. if ($r->protocol =~ /1\.1/) { my %vary = map {$_,1} qw(Accept-Encoding User-Agent); - if (my @vary = $r->header_out('Vary')) { - @vary{@vary} = (); + if (my $vary = $r->header_out('Vary')||0) { + $vary{$vary} = 1; } $r->header_out('Vary' => join ',', keys %vary); } @@ -56,8 +57,8 @@ if ($can_gzip) { $r->content_encoding('gzip'); $r->send_http_header; - local $/; - print Compress::Zlib::memGzip(<$fh>); +# $r->print( Compress::Zlib::memGzip(do {local $/; <$fh>}) ); + print( Compress::Zlib::memGzip(do {local $/; <$fh>}) ); } else { $r->send_http_header; $r->send_fd($fh); @@ -66,8 +67,47 @@ return OK; } -1; +sub can_gzip { + my $r = shift; + + my $how_decide = $r->dir_config('CompressDecision'); + if (!defined($how_decide) || lc($how_decide) eq 'header') { + return +($r->header_in('Accept-Encoding')||'') =~ /gzip/; + } elsif (lc($how_decide) eq 'user-agent') { + return guess_by_user_agent($r->header_in('User-Agent')); + } + + die "Unrecognized value '$how_decide' specified for CompressDecision"; +} + +sub guess_by_user_agent { + # This comes from Andreas' Apache::GzipChain. It's very out of + # date, though, I'd like it if someone sent me a better regex. + + my $ua = shift; + return $ua =~ m{ + ^Mozilla/ # They all start with Mozilla... + \d+\.\d+ # Version string + [\s\[\]\w\-]+ # Language + (?: + \(X11 # Any unix browser should work + | + Macint.+PPC,\sNav # Does this match anything?? + ) + }x; +} + 1; + +# Verbose version: +# my $content = do {local $/; <$fh>}; +# my $content_size = length($content); +# $content = Compress::Zlib::memGzip(\$content); +# my $compressed_size = length($content); +# my $ratio = int(100*$compressed_size/$content_size) if $content_size; +# print STDERR "GzipCompression $content_size/$compressed_size ($ratio%)\n"; +# print $content; + __END__ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:38 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:38 +0900 Subject: [Slashdotjp-dev 390] CVS update: slashjp/Slash/Custom/ApacheRegistryFilter Message-ID: <20060712114138.43AC72AC011@users.sourceforge.jp> Index: slashjp/Slash/Custom/ApacheRegistryFilter/ApacheRegistryFilter.pm diff -u slashjp/Slash/Custom/ApacheRegistryFilter/ApacheRegistryFilter.pm:1.1 slashjp/Slash/Custom/ApacheRegistryFilter/ApacheRegistryFilter.pm:1.2 --- slashjp/Slash/Custom/ApacheRegistryFilter/ApacheRegistryFilter.pm:1.1 Wed Dec 22 18:13:32 2004 +++ slashjp/Slash/Custom/ApacheRegistryFilter/ApacheRegistryFilter.pm Wed Jul 12 20:41:38 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ApacheRegistryFilter.pm,v 1.1 2004/12/22 09:13:32 oliver Exp $ +# $Id: ApacheRegistryFilter.pm,v 1.2 2006/07/12 11:41:38 sugi Exp $ # this merely overrides a "broken" method in Apache::SSI, # where include directives don't work for mixing with Apache::Compress @@ -18,7 +18,7 @@ use Apache::Constants qw(:common); -($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; sub handler ($$) { my ($class, $r) = @_ > 1 ? (shift, shift) : (__PACKAGE__, shift); @@ -39,13 +39,11 @@ # We temporarily override the header-sending routines to make them # noops. This lets people leave these methods in their scripts. - my $warn = $^W; - undef $^W; + no warnings 'redefine'; local *Apache::send_http_header = sub { $r->content_type($_[0]) if @_; }; local *Apache::send_cgi_header = sub {}; - $^W = $warn; $pr->SUPER::run(@_); } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:38 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:38 +0900 Subject: [Slashdotjp-dev 391] CVS update: slashjp/Slash/Custom/ApacheSSI Message-ID: <20060712114138.61F242AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Custom/ApacheSSI/ApacheSSI.pm diff -u slashjp/Slash/Custom/ApacheSSI/ApacheSSI.pm:1.1 slashjp/Slash/Custom/ApacheSSI/ApacheSSI.pm:1.2 --- slashjp/Slash/Custom/ApacheSSI/ApacheSSI.pm:1.1 Wed Dec 22 18:13:33 2004 +++ slashjp/Slash/Custom/ApacheSSI/ApacheSSI.pm Wed Jul 12 20:41:38 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ApacheSSI.pm,v 1.1 2004/12/22 09:13:33 oliver Exp $ +# $Id: ApacheSSI.pm,v 1.2 2006/07/12 11:41:38 sugi Exp $ # this merely overrides a "broken" method in Apache::SSI, # where include directives don't work for mixing with Apache::Compress @@ -16,9 +16,25 @@ use base 'Apache::SSI'; use vars qw($VERSION); -use Apache::Constants qw(:common OPT_INCNOEXEC); +use Apache::Constants qw(:common :http OPT_INCNOEXEC); -($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub output { + my $self = shift; + + my @parts = split m/()/s, $self->{'text'}; + while (@parts) { +# $self->{_r}->print( ('', shift @parts)[1-$self->{'suspend'}[0]] ); + print( ('', shift @parts)[1-$self->{'suspend'}[0]] ); + last unless @parts; + my $ssi = shift @parts; + if ($ssi =~ m/^$/s) { +# $self->{_r}->print( $self->output_ssi($1) ); + print( $self->output_ssi($1) ); + } else { die 'Parse error' } + } +} sub ssi_perl { my($self, $args, $margs) = @_; @@ -41,17 +57,16 @@ $self->error("Include of ", $subr->filename, " failed: $!"); } } else { - unless ($subr->run == OK) { - $self->error("Include of '@{[$subr->filename()]}' failed: $!"); + if ( $subr->status == HTTP_OK ) { + # Subrequests can fuck up %ENV, make sure it's restored upon exit. + # Unfortunately 'local(%ENV)=%ENV' reportedly causes segfaults. + my %save_ENV = %ENV; + $subr->run == OK + or $self->error("Include of '@{[$subr->filename()]}' failed: $!"); + %ENV = %save_ENV; } } - ## Make sure that all of the variables set in the include are present here. - #my $env = $subr->subprocess_env(); - #foreach ( keys %$env ) { - # $self->{_r}->subprocess_env($_, $env->{$_}); - #} - return ''; } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:38 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:38 +0900 Subject: [Slashdotjp-dev 392] CVS update: slashjp/Slash/Custom/ParUserAgent Message-ID: <20060712114138.808C72AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Custom/ParUserAgent/ParUserAgent.pm diff -u slashjp/Slash/Custom/ParUserAgent/ParUserAgent.pm:1.1 slashjp/Slash/Custom/ParUserAgent/ParUserAgent.pm:1.2 --- slashjp/Slash/Custom/ParUserAgent/ParUserAgent.pm:1.1 Wed Dec 22 18:13:33 2004 +++ slashjp/Slash/Custom/ParUserAgent/ParUserAgent.pm Wed Jul 12 20:41:38 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: ParUserAgent.pm,v 1.1 2004/12/22 09:13:33 oliver Exp $ +# $Id: ParUserAgent.pm,v 1.2 2006/07/12 11:41:38 sugi Exp $ # This overrides LWP::Parallel::UserAgent to allow multiple # proxies to be used with a single scheme, indeed with a @@ -19,7 +19,7 @@ use LWP::Parallel::UserAgent; -($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; sub _need_proxy { my($self, $url) = @_; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:38 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:38 +0900 Subject: [Slashdotjp-dev 393] CVS update: slashjp/Slash/DB Message-ID: <20060712114138.A0A762AC011@users.sourceforge.jp> Index: slashjp/Slash/DB/DB.pm diff -u slashjp/Slash/DB/DB.pm:1.3 slashjp/Slash/DB/DB.pm:1.4 --- slashjp/Slash/DB/DB.pm:1.3 Fri Dec 31 21:35:44 2004 +++ slashjp/Slash/DB/DB.pm Wed Jul 12 20:41:38 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: DB.pm,v 1.3 2004/12/31 12:35:44 oliver Exp $ +# $Id: DB.pm,v 1.4 2006/07/12 11:41:38 sugi Exp $ package Slash::DB; @@ -10,7 +10,7 @@ use Slash::DB::Utility; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: Would you cram a sock in it, Bender? @@ -41,9 +41,9 @@ $self->sqlConnect(); return $self; } elsif ($dsn) { - die "Database $dsn unsupported! (virtual user: $user)"; + die "Database $dsn unsupported! (virtual user '$user')"; } else { - die "DBIx::Password returned *nothing* for virtual user $user DSN (is the username correct?)"; + die "DBIx::Password has no information about the virtual user '$user'. Most likely either you mistyped it (maybe in slash.sites or your SlashVirtualUser directive?), or DBIx::Password is misconfigured somehow"; } } @@ -895,28 +895,6 @@ =back -=head2 deleteAuthor(KEY) - -I am the default documentation, short and stout. - -=over 4 - -=item Parameters - -=over 4 - -=item KEY - -Key, as in the KEY - -=back - -=item Return value - -Fixed KEY. - -=back - =head2 deleteTopic(KEY) I am the default documentation, short and stout. From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 394] CVS update: slashjp/Slash/DB/PostgreSQL Message-ID: <20060712114139.2373A2AC0D3@users.sourceforge.jp> Index: slashjp/Slash/DB/PostgreSQL/PostgreSQL.pm diff -u slashjp/Slash/DB/PostgreSQL/PostgreSQL.pm:1.2 slashjp/Slash/DB/PostgreSQL/PostgreSQL.pm:1.3 --- slashjp/Slash/DB/PostgreSQL/PostgreSQL.pm:1.2 Wed Dec 22 18:13:34 2004 +++ slashjp/Slash/DB/PostgreSQL/PostgreSQL.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: PostgreSQL.pm,v 1.2 2004/12/22 09:13:34 oliver Exp $ +# $Id: PostgreSQL.pm,v 1.3 2006/07/12 11:41:39 sugi Exp $ package Slash::DB::PostgreSQL; use strict; @@ -13,7 +13,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; # BENDER: I hate people who love me. And they hate me. From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 395] CVS update: slashjp/Slash/DB/Oracle Message-ID: <20060712114139.044172AC011@users.sourceforge.jp> Index: slashjp/Slash/DB/Oracle/Oracle.pm diff -u slashjp/Slash/DB/Oracle/Oracle.pm:1.2 slashjp/Slash/DB/Oracle/Oracle.pm:1.3 --- slashjp/Slash/DB/Oracle/Oracle.pm:1.2 Wed Dec 22 18:13:34 2004 +++ slashjp/Slash/DB/Oracle/Oracle.pm Wed Jul 12 20:41:38 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Oracle.pm,v 1.2 2004/12/22 09:13:34 oliver Exp $ +# $Id: Oracle.pm,v 1.3 2006/07/12 11:41:38 sugi Exp $ package Slash::DB::Oracle; @@ -9,7 +9,7 @@ use vars qw($VERSION @ISA); @ISA = qw( Slash::DB::Utility ); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; 1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 396] CVS update: slashjp/Slash/DB/Static/Oracle Message-ID: <20060712114139.6F1002AC0D3@users.sourceforge.jp> Index: slashjp/Slash/DB/Static/Oracle/Oracle.pm diff -u slashjp/Slash/DB/Static/Oracle/Oracle.pm:1.2 slashjp/Slash/DB/Static/Oracle/Oracle.pm:1.3 --- slashjp/Slash/DB/Static/Oracle/Oracle.pm:1.2 Wed Dec 22 18:13:35 2004 +++ slashjp/Slash/DB/Static/Oracle/Oracle.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Oracle.pm,v 1.2 2004/12/22 09:13:35 oliver Exp $ +# $Id: Oracle.pm,v 1.3 2006/07/12 11:41:39 sugi Exp $ package Slash::DB::Static::Oracle; use strict; @@ -11,7 +11,7 @@ use URI (); use vars qw($VERSION); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; 1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 397] CVS update: slashjp/Slash/DB/Static/MySQL Message-ID: <20060712114139.49E0C2AC011@users.sourceforge.jp> Index: slashjp/Slash/DB/Static/MySQL/MySQL.pm diff -u slashjp/Slash/DB/Static/MySQL/MySQL.pm:1.3 slashjp/Slash/DB/Static/MySQL/MySQL.pm:1.4 --- slashjp/Slash/DB/Static/MySQL/MySQL.pm:1.3 Fri Dec 31 21:35:45 2004 +++ slashjp/Slash/DB/Static/MySQL/MySQL.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: MySQL.pm,v 1.3 2004/12/31 12:35:45 oliver Exp $ +# $Id: MySQL.pm,v 1.4 2006/07/12 11:41:39 sugi Exp $ package Slash::DB::Static::MySQL; @@ -19,7 +19,7 @@ use vars qw($VERSION); use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: Hey, thinking hurts 'em! Maybe I can think of a way to use that. @@ -72,10 +72,14 @@ # For rss, rdf etc feeds, basically used by tasks. # Ultimately this should be subsumed into # getStoriesEssentials since they serve the same purpose. -# XXXSECTIONTOPICS let's get the NOW() out of here +# XXXSECTIONTOPICS let's get the NOW() out of here. +# This is much slower than getStoriesEssentials but fortunately +# is not called very often. Its calling code really should be +# rewritten to use getStoriesEssentials. sub getBackendStories { my($self, $options) = @_; + my $limit = $options->{limit} || 10; my $topic = $options->{topic} || getCurrentStatic('mainpage_nexus_tid'); my $select = "stories.stoid AS stoid, sid, title, stories.tid AS tid, primaryskid, time, @@ -88,7 +92,7 @@ AND stories.stoid = story_topics_rendered.stoid AND story_topics_rendered.tid=$topic"; - my $other = "ORDER BY time DESC LIMIT 10"; + my $other = "ORDER BY time DESC LIMIT $limit"; my $returnable = $self->sqlSelectAllHashrefArray($select, $from, $where, $other); @@ -105,6 +109,11 @@ for my $key (qw( image width height )) { $story->{image}{$key} = $topic_hr->{$key}; } + + # so we can assign proper "creator" if story was posted + # originally as a journal + my $journal_id = $self->getStory($story->{stoid}, 'journal_id'); + $story->{journal_id} = $journal_id if $journal_id; } return $returnable; @@ -157,8 +166,8 @@ my $topics = $self->getTopics; for my $topic (@$ar) { - @{ $topic }{qw(alttext image width height)} = - @{ $topics->{$topic->{tid}} }{qw(alttext image width height)}; + @{ $topic }{qw(textname image width height)} = + @{ $topics->{$topic->{tid}} }{qw(textname image width height)}; } return $ar; @@ -223,6 +232,55 @@ return $returnable; } +######################################################## +# For dbsparklines.pl +# This is a bit tricky because some moments may not have rows in +# the table, and times may not be exactly $resolution apart. +# We get the key-value hashref and walk it looking for +# appropriate rows. +sub getSparklineData { + my($self, $dbid, $col, $now, $resolution, $secs_back, $max, $multiplier) = @_; + $multiplier ||= 1; + + my $now_ut = timeCalc($now, "%s", 0); + my $start_ut = $now_ut - $secs_back; + my $now_q = $self->sqlQuote($now); + my $kv_hr = $self->sqlSelectAllKeyValue( + "UNIX_TIMESTAMP(ts) AS ut, $col", + "dbs_readerstatus", + "dbid=$dbid + AND ts >= DATE_SUB($now_q, INTERVAL $secs_back SECOND)"); + return [ ] unless %$kv_hr; + + my @ut = sort { $a <=> $b } keys %$kv_hr; + my @quantized = ( ); + my $t = $start_ut; + T: while ($t < $now_ut) { + my @q = ( ); + for my $t1 ($t .. $t + $resolution-1) { + push @q, $kv_hr->{$t1} * $multiplier if defined $kv_hr->{$t1}; + } + + # If nothing was found, no value for this quantized + # time value, push undef (GD::Graph knows what to + # do with that). Otherwise push the mean of the + # value(s) found. + my $q = undef; + for my $val (@q) { + $q ||= 0; + $q += $val; + } + if (defined $q) { + $q /= scalar @q; + $q = $max if $q > $max; + } + push @quantized, $q; + + $t += $resolution; + } + + return \@quantized; +} ######################################################## # For balance_readers.pl @@ -241,6 +299,8 @@ "dbid", "dbid, MIN(IF(was_alive='yes',1,0)) AS was_alive, + MIN(IF(was_reachable='yes',1,0)) AS was_reachable, + MIN(IF(was_running='yes',1,0)) AS was_running, AVG(slave_lag_secs) AS lag, AVG(query_bog_secs) AS bog", "dbs_readerstatus", @@ -324,7 +384,9 @@ my $days_back = $constants->{freshenup_text_render_daysback} || 7; return $self->sqlUpdate( "story_text, stories", - { rendered => undef }, + { rendered => undef, + -last_update => 'last_update' + }, "story_text.stoid = stories.stoid AND rendered IS NOT NULL AND time < DATE_SUB(NOW(), INTERVAL $days_back DAY)"); @@ -335,8 +397,9 @@ sub forgetUsersLogtokens { my($self) = @_; + # delete logtokens if they have been expired for a month return $self->sqlDelete("users_logtokens", - "DATE_ADD(expires, INTERVAL 1 MONTH) < NOW()"); + "public = 'no' AND DATE_ADD(expires, INTERVAL 1 MONTH) < NOW()"); } ######################################################## @@ -347,7 +410,8 @@ my $reader = getObject('Slash::DB', { db_type => "reader" }); my $min_lastlooktime = time - ($constants->{lastlookmemory} + 86400*7); my $uids = $reader->sqlSelectColArrayref("uid", "users_param", - "name='lastlooktime' AND value < '$min_lastlooktime'"); + "name='lastlooktime' AND value < '$min_lastlooktime'") || [ ]; + my $count = scalar @$uids; my $splice_count = 2000; while (@$uids) { @@ -356,6 +420,7 @@ $self->sqlDelete("users_param", "name IN ('lastlooktime', 'lastlookuid') AND uid IN ($uids_in)"); } + return $count; } ######################################################## @@ -367,7 +432,8 @@ my $max_hrs = $constants->{mailpass_max_hours} || 48; my $min_mailpass_last_ts = time - ($max_hrs*3600 + 86400*7); my $uids = $reader->sqlSelectColArrayref("uid", "users_param", - "name='mailpass_last_ts' AND value < '$min_mailpass_last_ts'"); + "name='mailpass_last_ts' AND value < '$min_mailpass_last_ts'") || [ ]; + my $count = scalar @$uids; my $splice_count = 2000; while (@$uids) { @@ -376,6 +442,7 @@ $self->sqlDelete("users_param", "name IN ('mailpass_last_ts', 'mailpass_num') AND uid IN ($uids_in)"); } + return $count; } ######################################################## @@ -515,7 +582,7 @@ sub forgetRemarks { my($self) = @_; return $self->sqlDelete("remarks", - "time < DATE_SUB(NOW(), INTERVAL 365 DAY)"); + "time < DATE_SUB(NOW(), INTERVAL 90 DAY)"); } ######################################################## @@ -524,29 +591,68 @@ my($self) = @_; my $constants = getCurrentStatic(); -# This is now done more efficiently, throughout the day, by the -# counthits.pl task. -# $self->updateStoriesCounts(); - $self->sqlDelete('badpasswords', "TO_DAYS(NOW()) - TO_DAYS(ts) > 2"); - $self->sqlDelete('pollvoters'); + $self->sqlDelete('discussions', "type='recycle' AND commentcount=0") + unless $constants->{noflush_empty_discussions}; + return 0; +} +######################################################## +# For run_moderatord.pl +# Pass in option "sleep_between" of a few seconds, maybe up to a +# minute, if for some reason the deletion still makes slave +# replication lag... (but it shouldn't, anymore) - 2005/01/06 +sub deleteOldModRows { + my($self, $options) = @_; + + my $reader = getObject('Slash::DB', { db_type => "reader" }); + my $constants = getCurrentStatic(); + my $max_rows = $constants->{mod_delete_maxrows} || 1000; my $archive_delay_mod = $constants->{archive_delay_mod} || $constants->{archive_delay} || 14; - $self->sqlDelete('moderatorlog', - "TO_DAYS(NOW()) - TO_DAYS(ts) > $archive_delay_mod"); - $self->sqlDelete('metamodlog', - "TO_DAYS(NOW()) - TO_DAYS(ts) > $archive_delay_mod"); - -# This is now done by the flush_formkeys task. -# my $delete_time = time() - $constants->{formkey_timeframe}; -# $self->sqlDelete('formkeys', "ts < $delete_time"); + my $sleep_between = $options->{sleep_between} || 0; - $self->sqlDelete('discussions', "type='recycle' AND commentcount=0") - unless $constants->{noflush_empty_discussions}; + # Find the minimum ID in these tables that should remain, then + # delete everything before it. We do it this way to keep the + # slave DBs tied up on the replication of the deletion query as + # little as possible. Turning off foreign key checking here is + # just pretty lame, I know... + + $self->sqlDo("SET FOREIGN_KEY_CHECKS=0"); + + # First delete from the bottom up for the moderatorlog. + + my $junk_bottom = $reader->sqlSelect('MIN(id)', 'moderatorlog'); + my $need_bottom = $reader->sqlSelectNumericKeyAssumingMonotonic( + 'moderatorlog', 'min', 'id', + "ts >= DATE_SUB(NOW(), INTERVAL $archive_delay_mod DAY)"); + while ($need_bottom && $junk_bottom < $need_bottom) { + $junk_bottom += $max_rows; + $junk_bottom = $need_bottom if $need_bottom < $junk_bottom; + $self->sqlDelete('moderatorlog', "id < $junk_bottom"); + sleep $sleep_between + if $sleep_between; + } + + # Now delete from the bottom up for the metamodlog. + + $junk_bottom = $reader->sqlSelect('MIN(id)', 'metamodlog'); + $need_bottom = $reader->sqlSelectNumericKeyAssumingMonotonic( + 'metamodlog', 'min', 'id', + "ts >= DATE_SUB(NOW(), INTERVAL $archive_delay_mod DAY)"); + while ($need_bottom && $junk_bottom < $need_bottom) { + $junk_bottom += $max_rows; + $junk_bottom = $need_bottom if $need_bottom < $junk_bottom; + $self->sqlDelete('metamodlog', "id < $junk_bottom"); + sleep $sleep_between + if $sleep_between && $junk_bottom < $need_bottom; + } + + $self->sqlDo("SET FOREIGN_KEY_CHECKS=1"); + return 0; } ######################################################## @@ -569,16 +675,24 @@ my $splice_count = 200; if ($constants->{subscribe} && !$constants->{subscribe_hits_only}) { my @gmt = gmtime(); - my $today = sprintf "%4d%02d%02d", $gmt[5] + 1900, $gmt[4] + 1, $gmt[3]; - my $ar = $self->sqlSelectAll( + my $hr = $self->sqlSelectAllKeyValue( "uid, lastclick", "users_hits", "TO_DAYS(NOW()) - TO_DAYS(lastclick) <= 1" ); my %uids_day = ( ); - for my $uid_ar (@$ar) { - my($uid, $lastclick) = @$uid_ar; - my $lastclick_day = substr($lastclick, 0, 8); + for my $uid (keys %$hr) { + my $lastclick = $hr->{$uid}; + if ($lastclick =~ /^(\d{4})(\d{2})(\d{2})/) { + # Timestamp field users_hits.lastclick is + # being given to us in MySQL 4.0 format + # of YYYYMMDDhhmmss. Convert it to the + # MySQL 4.1 and later format of + # YYYY-MM-DD. See also getUser and + # _getUser_do_selects. + $lastclick = "$1-$2-$3"; + } + my $lastclick_day = substr($lastclick, 0, 10); $uids_day{$lastclick_day}{$uid} = 1; } for my $day (keys %uids_day) { @@ -593,12 +707,12 @@ ); # If there is more to do, sleep for a moment so we don't # hit the DB too hard. - sleep 2 if @uids; + sleep int($splice_count/20+0.5) if @uids; } } } else { my @gmt = gmtime(time-86400); - my $yesterday = sprintf "%4d%02d%02d", $gmt[5] + 1900, $gmt[4] + 1, $gmt[3]; + my $yesterday = sprintf "%4d-%02d-%02d", $gmt[5] + 1900, $gmt[4] + 1, $gmt[3]; my $uids_ar = $self->sqlSelectColArrayref( "uid", "accesslog", @@ -617,7 +731,7 @@ ); # If there is more to do, sleep for a moment so we don't # hit the DB too hard. - Time::HiRes::sleep(0.2) if @uids; + sleep int($splice_count/20+0.5) if @uids; } } } @@ -642,16 +756,24 @@ "(lastaccess < DATE_SUB(NOW(), INTERVAL $days DAY) OR karma < $min_k) AND tokens > 0" ); - my $uids_in = join(",", sort @$uids_ar); - my $rows = 0; - if ($uids_in) { - $rows = $self->sqlUpdate( - "users_info", - { -tokens => "GREATEST(0, tokens - $perday)" }, - "uid IN ($uids_in) AND tokens > 0" - ); + my $decayed = 0; + my $splice_count = 200; + while (@$uids_ar) { + my @uid_chunk = splice @$uids_ar, 0, $splice_count; + my $uids_in = join(",", @uid_chunk); + my $rows = 0; + if ($uids_in) { + $rows = $self->sqlUpdate( + "users_info", + { -tokens => "GREATEST(0, tokens - $perday)" }, + "uid IN ($uids_in)" + ); + } + $decayed += $rows * $perday; + # If there is more to do, sleep for a moment so we don't + # hit the DB too hard. + sleep int($splice_count/20+0.5) if @$uids_ar; } - my $decayed = $rows * $perday; return $decayed; } @@ -940,10 +1062,15 @@ my $skinname = $skins->{ $tree->{$tid}{skid} }{name}; my $mp_tid = $constants->{mainpage_nexus_tid}; - for my $child_tid (sort { lc $tree->{$a}{textname} cmp lc $tree->{$b}{textname} } keys %{$tree->{$tid}{child}}) { + my @children = + sort { lc $tree->{$a}{textname} cmp lc $tree->{$b}{textname} } + grep { $tree->{$tid}{child}{$_} > 0 } # poisoned children don't count + keys %{$tree->{$tid}{child}}; + for my $child_tid (@children) { next unless $tree->{$child_tid}{nexus} && $tree->{$child_tid}{skid}; + $index{$skinname} ||= [ ]; if ($children{$child_tid}) { - push @{$index{$skinname}{$child_tid}}, $children{$child_tid}; + push @{$index{$skinname}}, $children{$child_tid}; next; } @@ -1000,13 +1127,15 @@ sub convert_tokens_to_points { my($self, $n_wanted) = @_; + my $reader = getObject("Slash::DB", { db_type => 'reader' }); + my $constants = getCurrentStatic(); my %granted = ( ); return unless $n_wanted; # Sanity check. - my $n_users = $self->countUsers(); + my $n_users = $reader->countUsers(); $n_wanted = int($n_users/10) if $n_wanted > int($n_users)/10; my $maxtokens = $constants->{maxtokens} || 60; @@ -1017,7 +1146,7 @@ $tokentrade = $maxtokens if $tokentrade > $maxtokens; # sanity check my $half_tokentrade = int($tokentrade/2); # another sanity check - my $uids = $self->sqlSelectColArrayref( + my $uids = $reader->sqlSelectColArrayref( "uid", "users_info", "tokens >= $half_tokentrade", @@ -1044,16 +1173,30 @@ # and seclev < 100. These aren't meaningful limitations, so these # updates should work as well. - Jamie 2002/08/08 # Actually I don't think these are needed at all. - Jamie 2003/09/09 - $self->sqlUpdate( - "users_comments", - { points => $maxpoints }, - "points > $maxpoints" - ); - $self->sqlUpdate( - "users_info", - { tokens => $maxtokens }, - "tokens > $maxtokens" - ); + # + # 2006/02/09: I still don't think they're needed, and they are + # causing lags in replication... + # Searching rows for update: + # The thread is doing a first phase to find all matching + # rows before updating them. This has to be done if the UPDATE + # is changing the index that is used to find the involved rows. + # ...so I'm removing these. I believe wherever the existing code + # increases points or tokens, it updates the oldvalue to + # LEAST(newvalue, maxvalue), so these adjustments should never + # change anything. + # 2006/02/12: The lag is due to a MySQL bug in 4.1.16 that is + # fixed in 4.1.18. + # Still, we shouldn't need these. +# $self->sqlUpdate( +# "users_comments", +# { points => $maxpoints }, +# "points > $maxpoints" +# ); +# $self->sqlUpdate( +# "users_info", +# { tokens => $maxtokens }, +# "tokens > $maxtokens" +# ); return \%granted; } @@ -1138,7 +1281,7 @@ return if $lastmaxid > $newmaxid; my $ac_uid = getCurrentStatic('anonymous_coward_uid'); $self->sqlDo("INSERT INTO accesslog_artcom (uid, ts, c)" - . " SELECT uid, AVG(ts) AS ts, COUNT(*) AS c" + . " SELECT uid, FROM_UNIXTIME(FLOOR(AVG(UNIX_TIMESTAMP(ts)))) AS ts, COUNT(*) AS c" . " FROM accesslog" . " WHERE id BETWEEN $lastmaxid AND $newmaxid" . " AND (op='article' OR op='comments')" @@ -1623,7 +1766,7 @@ # Lampe, C. and Resnick, P. "Slash(dot) and Burn: Moderation in a # Large Scale Conversation Space." Proceedings of the Conference on # Computer Human Interaction (SIGCHI). April 2004. Vienna, Austria. - # ACM Press. (Forthcoming.) + # ACM Press. # # The goal of _csq_bonuses is to reward moderators who take # a little extra effort, by giving them their next set of @@ -1656,21 +1799,23 @@ # conversation and 7% for late comments [fifth quintile]." # Here, quintile 5 is the latest 20% of the discussion, and # quintile 1 is the earliest 20%. - if ($mod_hr->{cid_percentile} > 80) { - $num *= $constants->{m2_consequences_bonus_quintile_5} || 1; - push @applied, 'quintile_5'; - } elsif ($mod_hr->{cid_percentile} > 60) { - $num *= $constants->{m2_consequences_bonus_quintile_4} || 1; - push @applied, 'quintile_4'; - } elsif ($mod_hr->{cid_percentile} > 40) { - $num *= $constants->{m2_consequences_bonus_quintile_3} || 1; - push @applied, 'quintile_3'; - } elsif ($mod_hr->{cid_percentile} > 20) { - $num *= $constants->{m2_consequences_bonus_quintile_2} || 1; - push @applied, 'quintile_2'; - } else { - $num *= $constants->{m2_consequences_bonus_quintile_1} || 1; - push @applied, 'quintile_1'; + if (defined $mod_hr->{cid_percentile}) { + if ($mod_hr->{cid_percentile} > 80) { + $num *= $constants->{m2_consequences_bonus_quintile_5} || 1; + push @applied, 'quintile_5'; + } elsif ($mod_hr->{cid_percentile} > 60) { + $num *= $constants->{m2_consequences_bonus_quintile_4} || 1; + push @applied, 'quintile_4'; + } elsif ($mod_hr->{cid_percentile} > 40) { + $num *= $constants->{m2_consequences_bonus_quintile_3} || 1; + push @applied, 'quintile_3'; + } elsif ($mod_hr->{cid_percentile} > 20) { + $num *= $constants->{m2_consequences_bonus_quintile_2} || 1; + push @applied, 'quintile_2'; + } else { + $num *= $constants->{m2_consequences_bonus_quintile_1} || 1; + push @applied, 'quintile_1'; + } } # If a Fair moderation was applied to a comment that was @@ -1770,6 +1915,13 @@ } } +# XXXSRCID This needs to actually be, like, written. +sub recalcAL2 { + my($self, $srcid) = @_; + my $log = $self->getAL2Log($srcid); + # remember to delete from memcached +} + ######################################################## # For dailyStuff # This should only be run once per day, if this isn't @@ -2011,10 +2163,25 @@ # files rewritten (which mainly means they have a row present # in the story_dirty table), starting with the most recent. sub getStoriesToRefresh { - my($self, $limit, $tid) = @_; + my($self, $limit, $tid, $options) = @_; + $options ||= {}; $limit ||= 10; my $tid_clause = ""; $tid_clause = " AND story_topics_rendered.tid = $tid" if $tid; + my $stoid_clause = ""; + + if ($options->{stoid}) { + my @stoids = ( ); + if (ref $options->{stoid} eq "ARRAY") { + @stoids = @{$options->{stoid}} + } elsif (!ref $options->{stoid}) { + push @stoids, $options->{stoid}; + } + if (@stoids) { + my $stoid_in = join ',', map { $self->sqlQuote($_) } @stoids; + $stoid_clause = " AND stories.stoid IN ($stoid_in) "; + } + } # Include story_topics_rendered in this select just to make # sure there is at least one topic assigned to such stories. @@ -2022,14 +2189,15 @@ # don't include neverdisplay stories. my $retval = $self->sqlSelectAllHashrefArray( "DISTINCT stories.stoid AS stoid, sid, primaryskid, title, time", - "stories, story_text, story_topics_rendered - LEFT JOIN story_dirty ON stories.stoid=story_dirty.stoid", + "story_text, story_topics_rendered, + stories LEFT JOIN story_dirty ON stories.stoid=story_dirty.stoid", "time < NOW() AND stories.primaryskid > 0 AND stories.stoid = story_text.stoid AND story_dirty.stoid IS NOT NULL AND stories.stoid = story_topics_rendered.stoid - $tid_clause", + $tid_clause + $stoid_clause", "ORDER BY time DESC LIMIT $limit"); return [ ] if !@$retval; @@ -2101,7 +2269,17 @@ story_topics_chosen story_topics_rendered )) { $rows += $self->sqlDelete($table, "stoid=$stoid"); } - $self->deleteDiscussion($discussion_id) if $discussion_id; + + if ($discussion_id && $story->{journal_id}) { + # journal_fix.pl task will revert discussion data later + # (although maybe better to make this happen immediately) + $self->sqlUpdate('journal_transfer', { + stoid => 0, + }, 'id=' . $self->sqlQuote($story->{journal_id})); + } elsif ($discussion_id) { + $self->deleteDiscussion($discussion_id); + } + $self->sqlDo("COMMIT"); $self->sqlDo("SET AUTOCOMMIT=1"); return $rows; @@ -2115,8 +2293,12 @@ my($self) = @_; my $sql; $sql = "REPLACE INTO authors_cache "; - $sql .= "SELECT users.uid, nickname, GREATEST(fakeemail, ''), - GREATEST(homepage, ''), 0, GREATEST(bio, ''), author "; + $sql .= "SELECT users.uid, nickname, + GREATEST(IF(fakeemail IS NULL, '', fakeemail), ''), + GREATEST(IF(homepage IS NULL, '', homepage), ''), + 0, + GREATEST(IF(bio IS NULL, '', bio), ''), + author "; $sql .= "FROM users, users_info "; $sql .= "WHERE users.author=1 "; $sql .= "AND users.uid=users_info.uid"; @@ -2124,9 +2306,12 @@ $self->sqlDo($sql); $sql = "REPLACE INTO authors_cache "; - $sql .= "SELECT users.uid, nickname, GREATEST(fakeemail, ''), - GREATEST(homepage, ''), count(stories.uid), - GREATEST(bio, ''), author "; + $sql .= "SELECT users.uid, nickname, + GREATEST(IF(fakeemail IS NULL, '', fakeemail), ''), + GREATEST(IF(homepage IS NULL, '', homepage), ''), + COUNT(stories.uid), + GREATEST(IF(bio IS NULL, '', bio), ''), + author "; $sql .= "FROM users, stories, users_info "; $sql .= "WHERE stories.uid=users.uid "; $sql .= "AND users.uid=users_info.uid GROUP BY stories.uid"; @@ -2213,11 +2398,13 @@ @uncommon_words = split / /, $uncommon_words; $self->sqlDo("LOCK TABLES uncommonstorywords LOW_PRIORITY WRITE"); + $self->sqlDo("SET AUTOCOMMIT=0"); $self->sqlDelete("uncommonstorywords"); for my $word (@uncommon_words) { - $self->sqlInsert("uncommonstorywords", { word => $word }, - { delayed => 1 }); + $self->sqlInsert("uncommonstorywords", { word => $word }); } + $self->sqlDo("COMMIT"); + $self->sqlDo("SET AUTOCOMMIT=1"); $self->sqlDo("UNLOCK TABLES"); } @@ -2259,12 +2446,6 @@ } ######################################################## -sub countAccesslogDaily { - my($self) = @_; - return $self->sqlCount("accesslog", "TO_DAYS(NOW()) - TO_DAYS(ts)=1"); -} - -######################################################## # For tasks/run_moderatord.pl sub countM2M1Ratios { my($self, $longterm) = @_; @@ -2288,6 +2469,13 @@ } ######################################################## +# For tasks/topic_tree_draw.pl +sub countStoriesWithTopic { + my($self, $tid) = @_; + return $self->sqlCount('story_topics_rendered', "tid=$tid"); +} + +######################################################## # For portald sub createRSS { my($self, $bid, $item) = @_; @@ -2458,14 +2646,12 @@ $yesterday = substr($yesterday, 0, 10); my $where = ''; if ($where) { - $where = "created_at < DATE_SUB('$yesterday 00:00',INTERVAL $num_days DAY)"; + $where = "created_at < DATE_SUB('$yesterday 00:00', INTERVAL $num_days DAY)"; } else { $where = "created_at < '$yesterday 00:00'"; } - return $self->sqlSelect( - "MAX(uid)", - "users_info", - $where); + return $self->sqlSelectNumericKeyAssumingMonotonic( + 'users_info', 'max', 'uid', $where); } ######################################################## @@ -2503,9 +2689,9 @@ my $num = $options->{num_wanted} || 10; my $min_uid = $self->getLastUIDCreatedBeforeDaysBack($daysback, $yesterday); - my $newaccounts = $self->sqlSelect('max(uid)','users') - $min_uid; - my $newnicks = {}; return [ ] unless $min_uid; + my $newaccounts = $self->countUsers({ max => 1 }) - $min_uid; + my $newnicks = {}; my $domains = $self->sqlSelectAllHashrefArray( "initdomain, COUNT(*) AS c", "users_info", @@ -2513,14 +2699,21 @@ "GROUP BY initdomain ORDER BY c DESC, initdomain LIMIT $num"); foreach my $domain (@$domains) { - my $nicks = $self->sqlSelectAll('nickname','users, users_info',"users.uid=users_info.uid AND users_info.uid >= $min_uid AND initdomain=".$self->sqlQuote($domain->{initdomain}),'ORDER BY users.uid DESC'); - my $length = 5 + length($domain->{initdomain}); + my $dom = $domain->{initdomain}; + my $dom_q = $self->sqlQuote($dom); + my $nicks = $self->sqlSelectAll( + 'nickname', + 'users, users_info', + "users.uid=users_info.uid AND users_info.uid >= $min_uid + AND initdomain=$dom_q", + 'ORDER BY users.uid DESC'); + my $length = 5 + length($dom); my $i = 0; - $newnicks->{$domain->{initdomain}} = ""; + $newnicks->{$dom} = ''; - while ($length + length($nicks->[$i][0]) + 2 < 78) { - $newnicks->{$domain->{initdomain}} .= ', ' unless !$i; - $newnicks->{$domain->{initdomain}} .= $nicks->[$i][0]; + while ($nicks->[$i] && $length + length($nicks->[$i][0]) + 2 < 78) { + $newnicks->{$dom} .= ', ' unless !$i; + $newnicks->{$dom} .= $nicks->[$i][0]; $length += length($nicks->[$i][0]) + 2; $i++; } @@ -2577,21 +2770,22 @@ my ($self, $options) = @_; my $ac_uid = getCurrentStatic('anonymous_coward_uid'); $options ||= {}; - my @where; - push @where, "ts > date_sub(NOW(),INTERVAL $options->{days_back} DAY)" if $options->{days_back}; + + my @where = ( ); + push @where, "ts > DATE_SUB(NOW(), INTERVAL $options->{days_back} DAY)" if $options->{days_back}; push @where, "cuid != $ac_uid" if $options->{no_anon_comments}; push @where, "id >= $options->{start_at_id}" if $options->{start_at_id}; push @where, "id <= $options->{end_at_id}" if $options->{end_at_id}; - push @where, "ipid is not null and ipid!=''" if $options->{need_defined_ipid}; + push @where, "ipid IS NOT NULL AND ipid != ''" if $options->{need_ipid}; my $where = join(" AND ", @where); my $mods = $self->sqlSelectAllHashref( [qw(uid cuid)], - "uid,cuid,count(*) as count", + "uid, cuid, COUNT(*) AS count", "moderatorlog", $where, - "group by uid, cuid"); + "GROUP BY uid, cuid"); return $mods; } @@ -2601,21 +2795,24 @@ my ($self, $options) = @_; my $ac_uid = getCurrentStatic('anonymous_coward_uid'); $options ||= {}; - my @where = ("moderatorlog.cid=comments.cid"); + + my @where = ( "moderatorlog.cid=comments.cid" ); push @where, "ts > date_sub(NOW(),INTERVAL $options->{days_back} DAY)" if $options->{days_back}; push @where, "cuid != $ac_uid" if $options->{no_anon_comments}; push @where, "cuid = $ac_uid" if $options->{only_anon_comments}; push @where, "id >= $options->{start_at_id}" if $options->{start_at_id}; push @where, "id <= $options->{end_at_id}" if $options->{end_at_id}; - push @where, "ipid is not null and ipid!=''" if $options->{need_defined_ipid}; + push @where, "comments.ipid IS NOT NULL AND comments.ipid!=''" if $options->{need_ipid}; + my $where = join(" AND ", @where); + my $mods = $self->sqlSelectAllHashref( [qw(uid ipid)], - "moderatorlog.uid as uid, comments.ipid as ipid, count(*) as count", - "moderatorlog,comments", + "moderatorlog.uid AS uid, comments.ipid AS ipid, COUNT(*) AS count", + "moderatorlog, comments", $where, - "group by uid, comments.ipid"); - + "GROUP BY uid, comments.ipid"); + return $mods; } @@ -2730,6 +2927,24 @@ ); } +sub getUrlsNeedingFirstCheck { + my($self) = @_; + return $self->sqlSelectAllHashrefArray("*", "urls", "last_attempt IS NULL", "ORDER BY url_id ASC"); +} + +sub getUrlsNeedingRefresh { + my($self, $limit) = @_; + $limit ||= 50; + return $self->sqlSelectAllHashrefArray( + "*", + "urls", + "last_attempt IS NOT NULL + AND believed_fresh_until IS NOT NULL + AND believed_fresh_until < NOW()", + "ORDER BY believed_fresh_until ASC LIMIT $limit" + ); +} + 1; __END__ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 398] CVS update: slashjp/Slash/DB/Static/PostgreSQL Message-ID: <20060712114139.90D062AC0D6@users.sourceforge.jp> Index: slashjp/Slash/DB/Static/PostgreSQL/PostgreSQL.pm diff -u slashjp/Slash/DB/Static/PostgreSQL/PostgreSQL.pm:1.2 slashjp/Slash/DB/Static/PostgreSQL/PostgreSQL.pm:1.3 --- slashjp/Slash/DB/Static/PostgreSQL/PostgreSQL.pm:1.2 Wed Dec 22 18:13:35 2004 +++ slashjp/Slash/DB/Static/PostgreSQL/PostgreSQL.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: PostgreSQL.pm,v 1.2 2004/12/22 09:13:35 oliver Exp $ +# $Id: PostgreSQL.pm,v 1.3 2006/07/12 11:41:39 sugi Exp $ package Slash::DB::Static::PostgreSQL; use strict; @@ -11,7 +11,7 @@ use base 'Slash::DB::PostgreSQL'; use base 'Slash::DB::Static::MySQL'; -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: Whoa, slow down. You're going a mile a minute. From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 399] CVS update: slashjp/Slash/DB/Utility Message-ID: <20060712114139.B4DA52AC0D7@users.sourceforge.jp> Index: slashjp/Slash/DB/Utility/Utility.pm diff -u slashjp/Slash/DB/Utility/Utility.pm:1.3 slashjp/Slash/DB/Utility/Utility.pm:1.4 --- slashjp/Slash/DB/Utility/Utility.pm:1.3 Fri Dec 31 21:35:45 2004 +++ slashjp/Slash/DB/Utility/Utility.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Utility.pm,v 1.3 2004/12/31 12:35:45 oliver Exp $ +# $Id: Utility.pm,v 1.4 2006/07/12 11:41:39 sugi Exp $ package Slash::DB::Utility; @@ -12,12 +12,13 @@ use Time::HiRes; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: Bender, if this is some kind of scam, I don't get it. You already # have my power of attorney. my $timeout = 30; # This should eventualy be a parameter that is configurable +my $query_ref_regex = qr{(HASH|ARRAY|SCALAR|GLOB|CODE|LVALUE|IO|REF)\(0x[0-9a-f]{3,16}\)}; # this too ######################################################## # Generic methods for libraries. @@ -286,6 +287,45 @@ return $id; } + +####################################################### +# set a system variable if necessary. this will only be +# good for the current session. don't forget to set it +# back anyway. +sub sqlSetVar { + my($self, $var, $value) = @_; + return if $ENV{GATEWAY_INTERFACE} && !getCurrentUser('is_admin'); + + # can't use sqlQuote for this, can't be quoted + $var =~ s/\W+//; # just in case + $value =~ s/\D+//; # ditto (any non-numeric vars we might adjust?) + + $self->sqlDo("SET $var = $value"); +} + +####################################################### +# get the value of a named system variable +sub sqlGetVar { + my($self, $var) = @_; + + # to mirror what we do in sqlSetVar + $var =~ s/\W+//; + + my $sql = "SHOW VARIABLES LIKE '$var'"; + my $sth = $self->{_dbh}->prepare($sql); + + if (!$sth->execute) { + $self->sqlErrorLog($sql); + $self->sqlConnect; + return undef; + } + + my($name, $value) = $sth->fetchrow; + $sth->finish; + return $value; +} + + ######################################################## # The SQL query logging methods # @@ -419,8 +459,17 @@ # Useful SQL Wrapper Functions ######################################################## +sub _refCheck { + my($self, $where) = @_; + return if !$where || $where !~ $query_ref_regex; + my @c = caller(1); + my $w2 = $where; $w2 =~ s/\s+/ /g; + warn scalar(gmtime) . " query text contains ref string ($c[0] $c[1] $c[2] $c[3]): $w2\n"; +} + sub sqlSelectMany { my($self, $select, $from, $where, $other, $options) = @_; + $self->_refCheck($where); my $distinct = ($options && $options->{distinct}) ? "DISTINCT" : ""; my $sql = "SELECT $distinct $select "; @@ -444,6 +493,7 @@ # $options is a hash, add optional pieces here. sub sqlSelect { my($self, $select, $from, $where, $other, $options) = @_; + $self->_refCheck($where); my $distinct = ($options && $options->{distinct}) ? "DISTINCT" : ""; my $sql = "SELECT $distinct $select "; $sql .= "FROM $from " if $from; @@ -473,6 +523,7 @@ ######################################################## sub sqlSelectArrayRef { my($self, $select, $from, $where, $other) = @_; + $self->_refCheck($where); my $sql = "SELECT $select "; $sql .= "FROM $from " if $from; $sql .= "WHERE $where " if $where; @@ -502,6 +553,7 @@ ########################################################## sub sqlCount { my($self, $table, $where) = @_; + $self->_refCheck($where); my $sql = "SELECT COUNT(*) AS count FROM $table"; $sql .= " WHERE $where" if $where; @@ -519,6 +571,7 @@ ######################################################## sub sqlSelectHashref { my($self, $select, $from, $where, $other) = @_; + $self->_refCheck($where); my $sql = "SELECT $select "; $sql .= "FROM $from " if $from; @@ -543,6 +596,7 @@ ######################################################## sub sqlSelectColArrayref { my($self, $select, $from, $where, $other, $options) = @_; + $self->_refCheck($where); my $distinct = ($options && $options->{distinct}) ? "DISTINCT" : ""; my $sql = "SELECT $distinct $select "; @@ -586,6 +640,7 @@ # array ref of all records sub sqlSelectAll { my($self, $select, $from, $where, $other) = @_; + $self->_refCheck($where); my $sql = "SELECT $select "; $sql .= "FROM $from " if $from; @@ -619,7 +674,8 @@ # returns: # hash ref of all records sub sqlSelectAllHashref { - my($self, $id, $select, $from, $where, $other) = @_; + my($self, $id, $select, $from, $where, $other, $options) = @_; + $self->_refCheck($where); # Yes, if $id is not in $select things will be bad # Allow $id to be an arrayref to collect multiple rows of results @@ -643,6 +699,11 @@ $reference = \%{$reference->{$row->{$next_id}}}; } %$reference = %$row; + if ($options->{thin}) { + for my $next_id (@$id) { + delete $reference->{$next_id}; + } + } } $sth->finish; $self->_querylog_finish($qlid); @@ -664,6 +725,7 @@ # array ref of all records sub sqlSelectAllHashrefArray { my($self, $select, $from, $where, $other) = @_; + $self->_refCheck($where); my $sql = "SELECT $select "; $sql .= "FROM $from " if $from; @@ -673,7 +735,7 @@ my $qlid = $self->_querylog_start("SELECT", $from); my $sth = $self->sqlSelectMany($select, $from, $where, $other); return undef unless $sth; - my @returnable; + my @returnable = ( ); while (my $row = $sth->fetchrow_hashref) { push @returnable, $row; } @@ -699,12 +761,15 @@ # hashref, keys first column, values the second sub sqlSelectAllKeyValue { my($self, $select, $from, $where, $other) = @_; + $self->_refCheck($where); my $sql = "SELECT $select "; $sql .= "FROM $from " if $from; $sql .= "WHERE $where " if $where; $sql .= "$other" if $other; + $self->sqlConnect() or return undef; + my $qlid = $self->_querylog_start("SELECT", $from); my $H = $self->{_dbh}->selectall_arrayref($sql); unless ($H) { @@ -722,8 +787,116 @@ } ######################################################## +# This is a little different from the other sqlSelect* methods. +# +# Its reason for existing is that sometimes, for performance reasons, +# you want to do a select on a large table that is limited by a key +# that differs from the column you actually want to limit by, though +# both of them increase (or decrease) together. For example, perhaps +# you want to do a SELECT on an accesslog table with millions of rows +# based on a range of accesslog.ts, but to make sure the query optimizer +# restricts by primary key, you'd prefer to determine the range of +# accesslog.id that spans the rows in question, and offer that as +# part of the WHERE clause as well. The optimizer doesn't know that +# the columns id and ts increase together, but you do. Telling the +# optimizer that it can restrict by the numeric key may not make your +# query faster, but it might, and in non-pathological situations it +# won't make it slower. +# +# This method will return a boundary value of a numeric key column +# based on an inequality test for a different column that must be +# approximately monotonic with the key. It will always return quickly, +# since it uses a binary search to narrow down the value sought, and +# all its SELECTs are primary key lookups. +# +# Note that there must not be "holes" in the table where a value of the +# numeric key is missing even though there are values present both above +# and below it, or the answer may impose an incorrectly strict limitation +# (this bug may be fixed in the future). This includes "holes" in the +# values for that key in the rows returned by the where clause. +# +# For example, if you wanted to count the number of distinct uids in +# a very large accesslog table in several hours, the easy way is: +# +# $c = $slashdb->sqlSelect("COUNT(DISTINCT uid)", "accesslog", +# "ts BETWEEN '2001-01-01 01:00:00' AND '2001-01-01 03:00:00'"); +# +# but it may be faster, and certainly won't be significantly slower, +# to do: +# +# $minid = $slashdb->sqlSelectNumericKeyAssumingMonotonic("accesslog", "min", "id", "ts >= '2001-01-01 01:00:00'"); +# $maxid = $slashdb->sqlSelectNumericKeyAssumingMonotonic("accesslog", "max", "id", "ts <= '2001-01-01 03:00:00'"); +# $c = $slashdb->sqlSelect("COUNT(DISTINCT uid)", "accesslog", +# "id BETWEEN $minid AND $maxid AND ts BETWEEN '2001-01-01 01:00:00' AND '2001-01-01 03:00:00'"); + +sub sqlSelectNumericKeyAssumingMonotonic { + my($self, $table, $minmax, $keycol, $clause) = @_; + $self->_refCheck($clause); + + # Set up $minmax appropriately. + $minmax = uc($minmax); + if ($minmax !~ /^(MIN|MAX)$/) { + die "sqlSelectNumericKeyAssumingMonotonic called with minmax='$minmax'"; + } + # In MixedCaps to avoid typo bugs and make the code perhaps + # a bit clearer. This is the opposite of $minmax. + my $MaxMin = $minmax eq 'MIN' ? 'MAX' : 'MIN'; + + # We pretend the "left" end of the table is the end pointed to + # by whichever direction $minmax points, and the "right" end + # is the end $MaxMin points to. + # First, seed the leftmost variable with the id at the left end + # of the table. + my $leftmost = $self->sqlSelect("$minmax($keycol)", $table); + # If no such id, the table is empty. + return undef unless $leftmost; + # If the test actually passes for that id, then it's not a + # failure at all, and we know our answer already. + return $leftmost if $self->sqlSelect($keycol, $table, "$keycol=$leftmost AND ($clause)"); + + # Next, seed the rightmost with the id at the right end. + my $rightmost = $self->sqlSelect("$MaxMin($keycol)", $table); + # If that test fails, then there are no rows satisfying the + # desired condition, so we know our answer. + return undef if !$self->sqlSelect($keycol, $table, "$keycol=$rightmost AND ($clause)"); + + # Now iterate a binary search into the table. + my $answer = undef; + while (!$answer) { + # If we're really close, just do the SELECT. + if (abs($leftmost - $rightmost) < 100) { + my($min, $max); + if ($minmax eq 'MIN') { $min = $leftmost; $max = $rightmost } + else { $min = $rightmost; $max = $leftmost } + $answer = $self->sqlSelect("$minmax($keycol)", $table, + "$keycol BETWEEN $min AND $max + AND ($clause)"); + if (!$answer) { + # Table may have changed, that's one of + # the risks of using this method. Return + # the approximately correct answer that + # was, at least at one time, valid. + $answer = $leftmost; + } + } + last if $answer; + # If we're not that close, narrow it down. + my $middle = int(($leftmost + $rightmost) / 2); + my $hit = $self->sqlSelect($keycol, $table, + "$keycol=$middle AND ($clause)"); + if ($hit) { + $rightmost = $middle; + } else { + $leftmost = $middle; + } + } + return $answer; +} + +######################################################## sub sqlUpdate { my($self, $tables, $data, $where, $options) = @_; + $self->_refCheck($where); # If no changes were passed in, there's nothing to do. # (And if we tried to proceed we'd generate an SQL error.) @@ -791,6 +964,7 @@ ######################################################## sub sqlDelete { my($self, $table, $where, $limit) = @_; + $self->_refCheck($where); return unless $table; my $sql = "DELETE FROM $table"; $sql .= " WHERE $where" if $where; @@ -805,7 +979,6 @@ sub sqlInsert { my($self, $table, $data, $options) = @_; my($names, $values); - # Hmmmmm... we can trust getCurrentStatic here? - Jamie # What's inside /*! */ will be treated as a comment by most # other SQL servers, but MySQL will parse it. Kinda pointless # since we've basically given up on ever supporting DBs other @@ -852,6 +1025,7 @@ ################################################################# sub sqlDo { my($self, $sql) = @_; + $self->_refCheck($sql); $self->sqlConnect() or return undef; my $rows = $self->{_dbh}->do($sql); unless ($rows) { @@ -871,7 +1045,7 @@ my($self, $sql) = @_; my $error = $self->sqlError || 'no error string'; - my @return = ("DB='$self->{virtual_user}'", "hostinfo='$self->{_dbh}->{mysql_hostinfo}'", $error); + my @return = ("virtuser='$self->{virtual_user}'", "hostinfo='$self->{_dbh}->{mysql_hostinfo}'", $error); push @return, $sql if $sql; errorLog(join ' -- ', @return); } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:39 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:39 +0900 Subject: [Slashdotjp-dev 400] CVS update: slashjp/Slash/Display Message-ID: <20060712114139.E30EB2AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Display/Display.pm diff -u slashjp/Slash/Display/Display.pm:1.3 slashjp/Slash/Display/Display.pm:1.4 --- slashjp/Slash/Display/Display.pm:1.3 Fri Dec 31 21:35:46 2004 +++ slashjp/Slash/Display/Display.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Display.pm,v 1.3 2004/12/31 12:35:46 oliver Exp $ +# $Id: Display.pm,v 1.4 2006/07/12 11:41:39 sugi Exp $ package Slash::Display; @@ -50,7 +50,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT @EXPORT_OK $CONTEXT %FILTERS $TEMPNAME); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw(slashDisplay slashDisplayName); @EXPORT_OK = qw(get_template); my(%objects); @@ -184,6 +184,15 @@ # and this is the only good way to get the actual name, # page, skin, we bite the bullet and do it $tempdata ||= $reader->getTemplateByName($name, [qw(tpid page skin)]); + + # might as well bail here if we can't find the template + if (!$tempdata) { + # restore our original values + $user->{currentSkin} = $origSkin; + $user->{currentPage} = $origPage; + return; + } + $TEMPNAME = "ID $tempdata->{tpid}, " . "$name;$tempdata->{page};$tempdata->{skin}"; } @@ -197,7 +206,8 @@ # we only populate $err if !$ret ... still, if $err # is false, then we assume everything is OK - my($err, $ret, $out); + my($err, $ret); + my $out = ''; { local $SIG{__WARN__} = \&tempWarn; @@ -250,14 +260,11 @@ # allow slashDisplay(NAME, DATA, RETURN) syntax if (! ref $opt) { - $opt = $opt == 1 ? { Return => 1 } : {}; + $opt = ($opt && $opt == 1) ? { Return => 1 } : {}; } if ($opt->{Skin} && $opt->{Skin} eq 'NONE') { $user->{currentSkin} = 'default'; - # light is a special case - } elsif ($user->{light}) { - $user->{currentSkin} = 'light'; } elsif ($opt->{Skin}) { $user->{currentSkin} = $opt->{Skin}; } @@ -333,22 +340,23 @@ # for a template and you don't want your tags running # up against each other. - Cliff 8/1/01 %FILTERS = ( - decode_entities => \&decode_entities, - fixparam => \&fixparam, - fixurl => \&fixurl, - fudgeurl => \&fudgeurl, - strip_paramattr => \&strip_paramattr, - strip_urlattr => \&strip_urlattr, - strip_anchor => \&strip_anchor, - strip_attribute => \&strip_attribute, - strip_code => \&strip_code, - strip_extrans => \&strip_extrans, - strip_html => \&strip_html, - strip_literal => \&strip_literal, - strip_nohtml => \&strip_nohtml, - strip_notags => \&strip_notags, - strip_plaintext => \&strip_plaintext, - strip_mode => [ $strip_mode, 1 ], + decode_entities => \&decode_entities, + fixparam => \&fixparam, + fixurl => \&fixurl, + fudgeurl => \&fudgeurl, + strip_paramattr => \&strip_paramattr, + strip_paramattr_nonhttp => \&strip_paramattr_nonhttp, + strip_urlattr => \&strip_urlattr, + strip_anchor => \&strip_anchor, + strip_attribute => \&strip_attribute, + strip_code => \&strip_code, + strip_extrans => \&strip_extrans, + strip_html => \&strip_html, + strip_literal => \&strip_literal, + strip_nohtml => \&strip_nohtml, + strip_notags => \&strip_notags, + strip_plaintext => \&strip_plaintext, + strip_mode => [ $strip_mode, 1 ], %FILTERS ); From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 401] CVS update: slashjp/Slash/Display/Plugin Message-ID: <20060712114140.126A62AC011@users.sourceforge.jp> Index: slashjp/Slash/Display/Plugin/Plugin.pm diff -u slashjp/Slash/Display/Plugin/Plugin.pm:1.3 slashjp/Slash/Display/Plugin/Plugin.pm:1.4 --- slashjp/Slash/Display/Plugin/Plugin.pm:1.3 Fri Dec 31 21:35:46 2004 +++ slashjp/Slash/Display/Plugin/Plugin.pm Wed Jul 12 20:41:39 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Plugin.pm,v 1.3 2004/12/31 12:35:46 oliver Exp $ +# $Id: Plugin.pm,v 1.4 2006/07/12 11:41:39 sugi Exp $ package Slash::Display::Plugin; @@ -12,7 +12,6 @@ =head1 SYNOPSIS - [% USE Slash %] [% Slash.someFunction('some data') %] [% Slash.db.someMethod(var1, var2) %] @@ -22,7 +21,7 @@ Call available exported functions from Slash and Slash::Utility from within your template. Also call methods from Slash::DB with the C method. Constants from Slash::Constants are -available. Invoke with C<[% USE Slash %]>. +available. C<[% Slash.version %]> gives the version of Slash. C<[% Slash.VERSION %]> (note case) gives the version @@ -64,7 +63,7 @@ use Slash::Utility (); use base qw(Template::Plugin); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # BENDER: Forget your stupid theme park! I'm gonna make my own! # With hookers! And blackjack! In fact, forget the theme park! From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 402] CVS update: slashjp/Slash/Display/Provider Message-ID: <20060712114140.348C12AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Display/Provider/Provider.pm diff -u slashjp/Slash/Display/Provider/Provider.pm:1.3 slashjp/Slash/Display/Provider/Provider.pm:1.4 --- slashjp/Slash/Display/Provider/Provider.pm:1.3 Fri Dec 31 21:35:46 2004 +++ slashjp/Slash/Display/Provider/Provider.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Provider.pm,v 1.3 2004/12/31 12:35:46 oliver Exp $ +# $Id: Provider.pm,v 1.4 2006/07/12 11:41:40 sugi Exp $ package Slash::Display::Provider; @@ -35,7 +35,7 @@ use File::Spec::Functions; use Slash::Utility::Environment; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; $DEBUG = $Template::Provider::DEBUG || 0 unless defined $DEBUG; # BENDER: Oh, no room for Bender, huh? Fine. I'll go build my own lunar From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 403] CVS update: slashjp/Slash/Hook Message-ID: <20060712114140.523802AC0D7@users.sourceforge.jp> Index: slashjp/Slash/Hook/Hook.pm diff -u slashjp/Slash/Hook/Hook.pm:1.2 slashjp/Slash/Hook/Hook.pm:1.3 --- slashjp/Slash/Hook/Hook.pm:1.2 Wed Dec 22 18:13:37 2004 +++ slashjp/Slash/Hook/Hook.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Hook.pm,v 1.2 2004/12/22 09:13:37 oliver Exp $ +# $Id: Hook.pm,v 1.3 2006/07/12 11:41:40 sugi Exp $ package Slash::Hook; use strict; @@ -16,7 +16,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw(slashHook); my %classes; @@ -25,40 +25,23 @@ my($param, $options) = @_; my $slashdb = getCurrentDB(); + my $retval = undef; my $hooks = $slashdb->getHooksByParam($param); for my $hook (@$hooks) { - my $class = $hook->{class}; - my $function = $class . '::' . $hook->{subroutine}; + my $function = $hook->{class} . '::' . $hook->{subroutine}; - if ($classes{$class}) { # already require'd - if ($classes{$class} eq 'NA') { # already failed - next; - } - } else { - eval "require $class"; # we cache because this is expensive, - # even if it has already succeeded or - # failed, just by doing the eval -- pudge - if ($@) { # failed - $classes{$class} = 'NA'; - next; - } else { # success! - $classes{$class} = 1; - } - } - - my $code; - { - no strict 'refs'; - $code = \&{ $function }; - } - if (defined (&$code)) { - unless ($code->($options)) { - errorLog("Failed executing hook ($param) - $function"); + my $code = loadCoderef($hook->{class}, $hook->{subroutine}); + if ($code) { + $retval = $code->($options); + if (! defined $retval) { + errorLog("Failed executing hook ($param) - $function: no return value"); } } else { errorLog("Failed trying to do hook ($param) - $function"); } } + + $retval; } 1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 404] CVS update: slashjp/Slash/Hook/Sample Message-ID: <20060712114140.76C612AC0DE@users.sourceforge.jp> Index: slashjp/Slash/Hook/Sample/Sample.pm diff -u slashjp/Slash/Hook/Sample/Sample.pm:1.2 slashjp/Slash/Hook/Sample/Sample.pm:1.3 --- slashjp/Slash/Hook/Sample/Sample.pm:1.2 Wed Dec 22 18:13:37 2004 +++ slashjp/Slash/Hook/Sample/Sample.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Sample.pm,v 1.2 2004/12/22 09:13:37 oliver Exp $ +# $Id: Sample.pm,v 1.3 2006/07/12 11:41:40 sugi Exp $ package Slash::Hook::Sample; use strict; @@ -13,7 +13,7 @@ # Shake well, serve warm. -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; sub sample { From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 405] CVS update: slashjp/Slash/Install Message-ID: <20060712114140.A1C552AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Install/Install.pm diff -u slashjp/Slash/Install/Install.pm:1.3 slashjp/Slash/Install/Install.pm:1.4 --- slashjp/Slash/Install/Install.pm:1.3 Fri Dec 31 21:35:46 2004 +++ slashjp/Slash/Install/Install.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Install.pm,v 1.3 2004/12/31 12:35:46 oliver Exp $ +# $Id: Install.pm,v 1.4 2006/07/12 11:41:40 sugi Exp $ package Slash::Install; use strict; @@ -17,7 +17,7 @@ # BENDER: Like most of life's problems, this one can be solved with bending. -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -144,7 +144,7 @@ my($self, $answer, $themes, $symlink) = @_; $themes ||= $self->{'_themes'}; - $self->_install($themes->{$answer}, $symlink); + $self->_install($themes->{$answer}, $symlink, 'theme'); } sub installThemes { @@ -153,8 +153,8 @@ for my $answer (@$answers) { for (keys %$themes) { - if ($answer eq $themes->{$_}{installorder}) { - $self->_install($themes->{$_}, $symlink, 0); + if ($answer eq $themes->{$_}{order}) { + $self->_install($themes->{$_}, $symlink, 'theme'); } } } @@ -164,7 +164,7 @@ my($self, $answer, $plugins, $symlink) = @_; $plugins ||= $self->{'_plugins'}; - $self->_install($plugins->{$answer}, $symlink, 1); + $self->_install($plugins->{$answer}, $symlink, 'plugin'); } sub installPlugins { @@ -174,12 +174,32 @@ for my $answer (@$answers) { for (keys %$plugins) { if ($answer eq $plugins->{$_}{order}) { - $self->_install($plugins->{$_}, $symlink, 1); + $self->_install($plugins->{$_}, $symlink, 'plugin'); } } } } +sub installTagbox { + my($self, $answer, $tagboxes, $symlink) = @_; + $tagboxes ||= $self->{'_tagboxes'}; + + $self->_install($tagboxes->{$answer}, $symlink, 'tagbox'); +} + +sub installTagboxes { + my($self, $answers, $tagboxes, $symlink) = @_; + $tagboxes ||= $self->{'_tagboxes'}; + + for my $answer (@$answers) { + for (keys %$tagboxes) { + if ($answer eq $tagboxes->{$_}{order}) { + $self->_install($tagboxes->{$_}, $symlink, 'tagbox'); + } + } + } +} + # Used internally by the _process_fh_into_sql method (which in # turn is used internally by the _install method). @@ -227,14 +247,16 @@ }; sub _install { - my($self, $hash, $symlink, $is_plugin) = @_; + my($self, $hash, $symlink, $type) = @_; + # Yes, performance wise this is questionable, if getValue() was # cached.... who cares this is the install. -Brian if ($self->exists('hash', $hash->{name})) { print STDERR "Plugin $hash->{name} has already been installed\n"; return; } - if ($is_plugin) { + + if ($type eq 'plugin') { return if $self->exists('plugin', $hash->{name}); $self->create({ @@ -247,7 +269,9 @@ value => $symlink ? 1 : 0, description => "$hash->{name} plugin files installed symlink?" }); - } else { + } + + if ($type eq 'theme') { # not sure if this is what we want, but leave it # in until someone complains. really, we should # have reinstall theme/plugin methods or @@ -259,20 +283,32 @@ return if $self->exists('theme', $hash->{name}); $self->create({ - name => 'theme', - value => $hash->{'name'}, - description => $hash->{'description'}, + name => 'theme', + value => $hash->{'name'}, + description => $hash->{'description'}, }); $self->create({ - name => 'theme_' . $hash->{name} . '_symlink', - value => $symlink ? 1 : 0, - description => "$hash->{name} theme files installed symlink?" + name => 'theme_' . $hash->{name} . '_symlink', + value => $symlink ? 1 : 0, + description => "$hash->{name} theme files installed symlink?" }); } + + if ($type eq 'tagbox') { + return if $self->exists('tagbox', $hash->{name}); + + $self->create({ + name => 'tagbox', + value => $hash->{'name'}, + description => $hash->{'description'}, + }); + } + my $driver = $self->getValue('db_driver'); my $prefix_site = $self->getValue('site_install_directory'); my %stuff = ( # [relative directory, executable] + css => ["htdocs", 1], htdoc => ["htdocs", 1], htdoc_code => ["htdocs/code", 0], htdoc_faq => ["htdocs/faq", 0], @@ -381,7 +417,7 @@ } } - unless ($is_plugin) { + if ($type eq "theme") { my(%templates, @no_templates); for my $name (@{$hash->{'include_theme'}}) { my $slash_prefix = $self->get('base_install_directory')->{value}; @@ -455,7 +491,7 @@ } } - unless ($is_plugin) { + if ($type eq "theme") { # This is where we cleanup any templates that don't belong for (@{$hash->{'no-template'}}) { my($name, $page, $skin) = split /;/, $_; @@ -484,6 +520,13 @@ return $theme_list; } +sub getTagboxList { + my $tagbox_list = _getList(@_, 'tagboxes', 'TAGBOX'); + setListOrder($tagbox_list); + setListInstallOrder($tagbox_list); + return $tagbox_list; +} + sub getSiteTemplates { my($self) = @_; my (%templates, @no_templates, @final); @@ -575,7 +618,7 @@ my($key, $val) = split(/=/, $_, 2); $key = lc $key; if ($key =~ /^( - htdoc | htdoc_code | htdoc_faq | + css | htdoc | htdoc_code | htdoc_faq | image | image_award | image_banner | image_faq | no-template | include_theme | task | template | sbin | misc | topic )s?$/x) { From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 406] CVS update: slashjp/Slash/Test Message-ID: <20060712114140.C1BAF2AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Test/Test.pm diff -u slashjp/Slash/Test/Test.pm:1.3 slashjp/Slash/Test/Test.pm:1.4 --- slashjp/Slash/Test/Test.pm:1.3 Fri Dec 31 21:35:47 2004 +++ slashjp/Slash/Test/Test.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Test.pm,v 1.3 2004/12/31 12:35:47 oliver Exp $ +# $Id: Test.pm,v 1.4 2006/07/12 11:41:40 sugi Exp $ package Slash::Test; @@ -56,7 +56,13 @@ Will export everything from Slash, Slash::Utility, Slash::Display, Slash::Constants, Slash::XML, and Data::Dumper into the current namespace. Will export $user, $anon, $form, $constants, $slashdb, and $gSkin as global -variables into the current namespace. +variables into the current namespace, along with a few other useful +variables: $self (alias to $slashdb), $reader_db, $log_db, $writer_db, +and $search_db. + +Also the name of each plugin will be a global variable referencing its +object (e.g., C<$journal> is automatically created as a L +object). So use it one of three ways (use the default Virtual User, or pass it in via the import list, or pass in with slashTest()), and then @@ -94,7 +100,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = ( @Slash::EXPORT, @Slash::Constants::EXPORT_OK, @@ -146,7 +152,8 @@ =item Side effects Set up the environment with createEnvironment(), export $user, $anon, -$form, $constants, $slashdb, and $gSkin into current namespace. +$form, $constants, $slashdb, and $gSkin into current namespace. $self +is an alias to $slashdb. =back @@ -163,7 +170,7 @@ setCurrentSkin(determineCurrentSkin()); - $::slashdb = getCurrentDB(); + $::self = $::slashdb = getCurrentDB(); $::constants = getCurrentStatic(); $::user = getCurrentUser(); $::anon = getCurrentAnonymousCoward(); @@ -279,4 +286,4 @@ =head1 VERSION -$Id: Test.pm,v 1.3 2004/12/31 12:35:47 oliver Exp $ +$Id: Test.pm,v 1.4 2006/07/12 11:41:40 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:40 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:40 +0900 Subject: [Slashdotjp-dev 407] CVS update: slashjp/Slash/Utility Message-ID: <20060712114140.E0C9B2AC0D7@users.sourceforge.jp> Index: slashjp/Slash/Utility/Utility.pm diff -u slashjp/Slash/Utility/Utility.pm:1.2 slashjp/Slash/Utility/Utility.pm:1.3 --- slashjp/Slash/Utility/Utility.pm:1.2 Wed Dec 22 18:13:38 2004 +++ slashjp/Slash/Utility/Utility.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Utility.pm,v 1.2 2004/12/22 09:13:38 oliver Exp $ +# $Id: Utility.pm,v 1.3 2006/07/12 11:41:40 sugi Exp $ package Slash::Utility; @@ -38,7 +38,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = ( @Slash::Utility::Access::EXPORT, @Slash::Utility::Anchor::EXPORT, From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:41 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:41 +0900 Subject: [Slashdotjp-dev 408] CVS update: slashjp/Slash/Utility/Access Message-ID: <20060712114141.0D0922AC0D3@users.sourceforge.jp> Index: slashjp/Slash/Utility/Access/Access.pm diff -u slashjp/Slash/Utility/Access/Access.pm:1.3 slashjp/Slash/Utility/Access/Access.pm:1.4 --- slashjp/Slash/Utility/Access/Access.pm:1.3 Fri Dec 31 21:35:47 2004 +++ slashjp/Slash/Utility/Access/Access.pm Wed Jul 12 20:41:40 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Access.pm,v 1.3 2004/12/31 12:35:47 oliver Exp $ +# $Id: Access.pm,v 1.4 2006/07/12 11:41:40 sugi Exp $ package Slash::Utility::Access; @@ -30,12 +30,12 @@ use Slash::Utility::Data; use Slash::Utility::Environment; use Slash::Utility::System; -use Slash::Constants qw(:web :people); +use Slash::Constants qw(:web :people :messages); use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( checkFormPost formkeyError @@ -393,11 +393,13 @@ if ($slashdb->checkTimesPosted($formname, $max, $id, $formkey_earliest)) { undef $formkey unless $formkey =~ /^\w{10}$/; - unless ($formkey && $slashdb->checkFormkey($formkey_earliest, $formname, $id, $formkey)) { - $slashdb->createAbuse("invalid form key", $formname, $ENV{QUERY_STRING}); - $$err_message = Slash::getData('invalidformkey', '', ''); - return; - } +# wtf? no method checkFormkey exists ... +# of course, checkFormPost is never even called ... +# unless ($formkey && $slashdb->checkFormkey($formkey_earliest, $formname, $id, $formkey)) { +# $slashdb->createAbuse("invalid form key", $formname, $ENV{QUERY_STRING}); +# $$err_message = Slash::getData('invalidformkey', '', ''); +# return; +# } if (submittedAlready($formkey, $formname, $err_message)) { $slashdb->createAbuse("form already submitted", $formname, $ENV{QUERY_STRING}); @@ -520,6 +522,12 @@ my($formname, $field, $content, $wsfactor) = @_; $wsfactor ||= 1; + # If no content (or I suppose the single char '0') is passed in, + # just report that it passes the test. Hopefully the caller is + # performing other checks to make sure that boundary condition + # is addresses. + return 1 if !$content; + my $slashdb = getCurrentDB(); my $constants = getCurrentStatic(); my $user = getCurrentUser(); @@ -732,8 +740,7 @@ my $reg_subj = Slash::getData('rereg_email_subject', '', ''); - # Send the message (message code == -2) - doEmail($uid, $reg_subj, $reg_msg, -2); + doEmail($uid, $reg_subj, $reg_msg, MSG_CODE_REGISTRATION); } else { # We only need to clear these. $slashdb->setUser($uid, { @@ -811,4 +818,4 @@ =head1 VERSION -$Id: Access.pm,v 1.3 2004/12/31 12:35:47 oliver Exp $ +$Id: Access.pm,v 1.4 2006/07/12 11:41:40 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:41 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:41 +0900 Subject: [Slashdotjp-dev 422] CVS update: slashjp/Slash/Utility/Anchor Message-ID: <20060712114141.2F5672AC0D6@users.sourceforge.jp> Index: slashjp/Slash/Utility/Anchor/Anchor.pm diff -u slashjp/Slash/Utility/Anchor/Anchor.pm:1.6 slashjp/Slash/Utility/Anchor/Anchor.pm:1.7 --- slashjp/Slash/Utility/Anchor/Anchor.pm:1.6 Tue Oct 18 20:01:04 2005 +++ slashjp/Slash/Utility/Anchor/Anchor.pm Wed Jul 12 20:41:41 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Anchor.pm,v 1.6 2005/10/18 11:01:04 tach Exp $ +# $Id: Anchor.pm,v 1.7 2006/07/12 11:41:41 sugi Exp $ package Slash::Utility::Anchor; @@ -28,7 +28,6 @@ use Apache; use Apache::Constants ':http'; use Digest::MD5 'md5_hex'; -use Encode 'encode_utf8'; use Slash::Display; use Slash::Utility::Data; use Slash::Utility::Display; @@ -37,7 +36,7 @@ use base 'Exporter'; use vars qw($VERSION @EXPORT); -($VERSION) = ' $Revision: 1.6 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.7 $ ' =~ /\$Revision:\s+([^\s]+)/; @EXPORT = qw( http_send header @@ -143,9 +142,6 @@ # $r->header_out('Cache-Control', 'private'); # } - $options->{last_modified} && - $r->header_out('Last-Modified', $options->{last_modified}); - $r->send_http_header; return if $r->header_only; } @@ -195,6 +191,7 @@ # Should we also pass thru {page} here or is that outdated? #print STDERR "header(options->page) defined: '$options->{page}' for title '$data->{title}'\n" if defined($options->{page}); $data->{tab_selected} = $options->{tab_selected} if $options->{tab_selected}; + $data->{nopageid} = $options->{nopageid}; if ($options->{admin} && $user->{is_admin}) { $user->{state}{adminheader} = 1; @@ -269,7 +266,7 @@ if ($opt->{etag} || $opt->{do_etag}) { if ($opt->{do_etag} && $opt->{content}) { - $opt->{etag} = md5_hex(encode_utf8($opt->{content})); + $opt->{etag} = md5_hex($opt->{content}); } $r->header_out('ETag', $opt->{etag}); @@ -284,13 +281,18 @@ if ($opt->{filename}) { $opt->{filename} =~ s/[^\w_.-]/_/g; my $val = "filename=$opt->{filename}"; - $val = "attachment; $val" if $opt->{attachment}; + # none by default, MSIE etc. had problems? + if ($opt->{dis_type}) { + $opt->{dis_type} =~ s/\W+//; + $val = "$opt->{dis_type}; $val"; + } $r->header_out('Content-Disposition', $val); } $r->status($opt->{status}); $r->send_http_header; $r->rflush; +#print STDERR "http_send sent, header_only='" . ($r->header_only) . "' length(content)='" . length($opt->{content}) ."'\n"; return 1 if $r->header_only; if ($opt->{content}) { @@ -343,7 +345,7 @@ my $display; if ($form->{ssi} && $form->{ssi} eq 'yes') { - ssiHeadFoot('footer', $options); + ssiHeadFoot('footer', $options); return 1; } @@ -432,10 +434,15 @@ # if there's a special .inc header for this page, use it, else it's # business as usual. - $page = '' unless ($page ne 'misc' && $slashdb->existsTemplate({ - name => $headorfoot, - skin => $gSkin->{name}, - page => $user->{currentPage} })); + $page = '' unless ($page ne 'misc' && + $slashdb->existsTemplate({ + name => $headorfoot, + skin => $gSkin->{name}, + page => $user->{currentPage} + }) + + ); + my $ssiheadorfoot = 'ssi' . substr($headorfoot, 0, 4); @@ -626,7 +633,7 @@ # sometimes, when this is called from shtml, the section is not # in $user like we'd like it to be. This attempts to remedy this. # --Pater - $user->{currentSection} = $constants->{static_section} if $user->{currentSection} eq ''; + $user->{currentSection} = $constants->{static_section} if !defined($user->{currentSection}) || $user->{currentSection} eq ''; unless ($ENV{SCRIPT_NAME}) { # When run from a slashd task (or from the command line in @@ -641,10 +648,9 @@ # If this is the first time that getAd() is being called, we have # to set up all the ad data at once before we can return anything. if (!defined $user->{state}{ad}) { - if ($constants->{use_minithin} && $constants->{plugin}{MiniThin}) { - # new way - my $minithin = getObject('Slash::MiniThin', { db_type => 'reader' }); - $minithin->minithin; + if ($constants->{use_falk} && $constants->{plugin}{Falk}) { + my $falk = getObject('Slash::Falk', { db_type => 'reader' }); + $falk->falk; } else { # old way prepAds(); @@ -654,17 +660,18 @@ if ($num == 2 && $need_box) { # we need the ad wrapped in a fancybox if (defined $user->{state}{ad}{$num} + && $user->{state}{ad}{$num} =~ /\S/ && $user->{state}{ad}{$num} !~ /^ [% @@ -69,4 +69,4 @@ -%] __version__ -$Id: data;email;default,v 1.3 2004/12/31 12:35:53 oliver Exp $ +$Id: data;email;default,v 1.4 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/dispStory;email;default diff -u slashjp/plugins/Email/templates/dispStory;email;default:1.3 slashjp/plugins/Email/templates/dispStory;email;default:1.4 --- slashjp/plugins/Email/templates/dispStory;email;default:1.3 Fri Dec 31 21:35:53 2004 +++ slashjp/plugins/Email/templates/dispStory;email;default Wed Jul 12 20:41:48 2006 @@ -32,9 +32,7 @@ IF constants.use_dept; box(" from the $story.dept dept."); END; - thisurl = Slash.url2abs( - Slash.db.getSection(story.section, 'rootdir'), gSkin.absolutedir) || - gSkin.absolutedir; + thisurl = Slash.url2abs(Slash.db.getSection(story.primaryskid, 'rootdir'), absolutedir) || absolutedir; stime = Slash.timeCalc(story.time, "%A %B %d, @%H:%M"); box(" posted by $author on $stime ($topicname)"); @@ -58,7 +56,7 @@ To opt-out of further emailings: [% thisurl %]/email.pl?op=optout_form -Copyright 1997-2004 [% constants.sitepublisher %]. All rights reserved. +Copyright 1997-2005 [% constants.sitepublisher %]. All rights reserved. __version__ -$Id: dispStory;email;default,v 1.3 2004/12/31 12:35:53 oliver Exp $ +$Id: dispStory;email;default,v 1.4 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/emailOptoutForm;email;default diff -u slashjp/plugins/Email/templates/emailOptoutForm;email;default:1.2 slashjp/plugins/Email/templates/emailOptoutForm;email;default:1.3 --- slashjp/plugins/Email/templates/emailOptoutForm;email;default:1.2 Fri Dec 31 21:35:53 2004 +++ slashjp/plugins/Email/templates/emailOptoutForm;email;default Wed Jul 12 20:41:48 2006 @@ -21,17 +21,17 @@ width="99%" title="Opt-Out of Story Mailings" -%] -
+ [% IF form.formkey -%] - + [% END -%] - + -Enter email address to be removed from further story mailings:
- -

- -
+Enter email address to be removed from further story mailings:
+ +

+ + __version__ -$Id: emailOptoutForm;email;default,v 1.2 2004/12/31 12:35:53 oliver Exp $ +$Id: emailOptoutForm;email;default,v 1.3 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/emailStoryForm;email;default diff -u slashjp/plugins/Email/templates/emailStoryForm;email;default:1.2 slashjp/plugins/Email/templates/emailStoryForm;email;default:1.3 --- slashjp/plugins/Email/templates/emailStoryForm;email;default:1.2 Fri Dec 31 21:35:53 2004 +++ slashjp/plugins/Email/templates/emailStoryForm;email;default Wed Jul 12 20:41:48 2006 @@ -22,28 +22,28 @@ width="99%" title="Email a Story" -%] -
+ [% IF form.formkey -%] - + [% END -%] - + [% IF form.sid -%] - + [% END -%] [% UNLESS form.sid -%] -

Enter story ID to mail: - +

Enter story ID to mail: + [% ELSE -%] -Selected story: [% story.title %] -[% Slash.timeCalc(story.time) %] ([% story.sid %]) - +Selected story: [% story.title %] +[% Slash.timeCalc(story.time) %] ([% story.sid %]) + [% END -%] -

Enter email address to send story to: - -

-

+

Enter email address to send story to: + +

+ __version__ -$Id: emailStoryForm;email;default,v 1.2 2004/12/31 12:35:53 oliver Exp $ +$Id: emailStoryForm;email;default,v 1.3 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/email_subj;email;default diff -u slashjp/plugins/Email/templates/email_subj;email;default:1.1.1.1 slashjp/plugins/Email/templates/email_subj;email;default:1.2 --- slashjp/plugins/Email/templates/email_subj;email;default:1.1.1.1 Wed Jan 28 06:54:14 2004 +++ slashjp/plugins/Email/templates/email_subj;email;default Wed Jul 12 20:41:48 2006 @@ -16,4 +16,4 @@ __template__ [% story.title %] __version__ -$Id: email_subj;email;default,v 1.1.1.1 2004/01/27 21:54:14 oliver Exp $ +$Id: email_subj;email;default,v 1.2 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/optout_confirm;email;default diff -u slashjp/plugins/Email/templates/optout_confirm;email;default:1.1.1.1 slashjp/plugins/Email/templates/optout_confirm;email;default:1.2 --- slashjp/plugins/Email/templates/optout_confirm;email;default:1.1.1.1 Wed Jan 28 06:54:14 2004 +++ slashjp/plugins/Email/templates/optout_confirm;email;default Wed Jul 12 20:41:48 2006 @@ -19,4 +19,4 @@ If this request has been made in error, please send an email to [% constants.adminmail %]. __version__ -$Id: optout_confirm;email;default,v 1.1.1.1 2004/01/27 21:54:14 oliver Exp $ +$Id: optout_confirm;email;default,v 1.2 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/optout_subj;email;default diff -u slashjp/plugins/Email/templates/optout_subj;email;default:1.1.1.1 slashjp/plugins/Email/templates/optout_subj;email;default:1.2 --- slashjp/plugins/Email/templates/optout_subj;email;default:1.1.1.1 Wed Jan 28 06:54:14 2004 +++ slashjp/plugins/Email/templates/optout_subj;email;default Wed Jul 12 20:41:48 2006 @@ -17,4 +17,4 @@ __template__ Story Mailing Opt-out Confirmation __version__ -$Id: optout_subj;email;default,v 1.1.1.1 2004/01/27 21:54:14 oliver Exp $ +$Id: optout_subj;email;default,v 1.2 2006/07/12 11:41:48 sugi Exp $ Index: slashjp/plugins/Email/templates/removeOptoutForm;email;default diff -u slashjp/plugins/Email/templates/removeOptoutForm;email;default:1.2 slashjp/plugins/Email/templates/removeOptoutForm;email;default:1.3 --- slashjp/plugins/Email/templates/removeOptoutForm;email;default:1.2 Fri Dec 31 21:35:53 2004 +++ slashjp/plugins/Email/templates/removeOptoutForm;email;default Wed Jul 12 20:41:48 2006 @@ -21,14 +21,14 @@ width="99%" title="Remove an Email Address from Opt-out List" -%] -

- + + -Enter email address to be removed from the opt-out list:
- -

- -
+Enter email address to be removed from the opt-out list:
+ +

+ + __version__ -$Id: removeOptoutForm;email;default,v 1.2 2004/12/31 12:35:53 oliver Exp $ +$Id: removeOptoutForm;email;default,v 1.3 2006/07/12 11:41:48 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:49 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:49 +0900 Subject: [Slashdotjp-dev 441] CVS update: slashjp/plugins/Hof Message-ID: <20060712114149.3C5092AC103@users.sourceforge.jp> Index: slashjp/plugins/Hof/Hof.pm diff -u slashjp/plugins/Hof/Hof.pm:1.3 slashjp/plugins/Hof/Hof.pm:1.4 --- slashjp/plugins/Hof/Hof.pm:1.3 Fri Dec 31 21:36:48 2004 +++ slashjp/plugins/Hof/Hof.pm Wed Jul 12 20:41:49 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Hof.pm,v 1.3 2004/12/31 12:36:48 oliver Exp $ +# $Id: Hof.pm,v 1.4 2006/07/12 11:41:49 sugi Exp $ package Slash::Hof; @@ -11,7 +11,7 @@ use vars qw($VERSION); use base 'Slash::DB::Utility'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: And where would a giant nerd be? THE LIBRARY! @@ -120,8 +120,8 @@ my($self) = @_; my $stories = $self->sqlSelectAll( 'stories.sid, title, primaryskid, hits, users.nickname', - "stories, story_text, users - LEFT JOIN story_param + "story_text, users, + stories LEFT JOIN story_param ON stories.stoid=story_param.stoid AND story_param.name='neverdisplay'", 'stories.stoid=story_text.stoid AND story_param.name IS NULL Index: slashjp/plugins/Hof/PLUGIN diff -u slashjp/plugins/Hof/PLUGIN:1.2 slashjp/plugins/Hof/PLUGIN:1.3 --- slashjp/plugins/Hof/PLUGIN:1.2 Fri Dec 24 05:13:37 2004 +++ slashjp/plugins/Hof/PLUGIN Wed Jul 12 20:41:49 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:37 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:49 sugi Exp $ name=Hof description="High score stuff" htdoc=hof.pl Index: slashjp/plugins/Hof/hof.pl diff -u slashjp/plugins/Hof/hof.pl:1.3 slashjp/plugins/Hof/hof.pl:1.4 --- slashjp/plugins/Hof/hof.pl:1.3 Fri Dec 31 21:36:48 2004 +++ slashjp/plugins/Hof/hof.pl Wed Jul 12 20:41:49 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: hof.pl,v 1.3 2004/12/31 12:36:48 oliver Exp $ +# $Id: hof.pl,v 1.4 2006/07/12 11:41:49 sugi Exp $ use strict; use Slash; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:49 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:49 +0900 Subject: [Slashdotjp-dev 442] CVS update: slashjp/plugins/HumanConf Message-ID: <20060712114149.899D92AC105@users.sourceforge.jp> Index: slashjp/plugins/HumanConf/HumanConf.pm diff -u slashjp/plugins/HumanConf/HumanConf.pm:1.3 slashjp/plugins/HumanConf/HumanConf.pm:1.4 --- slashjp/plugins/HumanConf/HumanConf.pm:1.3 Fri Dec 31 21:36:48 2004 +++ slashjp/plugins/HumanConf/HumanConf.pm Wed Jul 12 20:41:49 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: HumanConf.pm,v 1.3 2004/12/31 12:36:48 oliver Exp $ +# $Id: HumanConf.pm,v 1.4 2006/07/12 11:41:49 sugi Exp $ package Slash::HumanConf; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -191,7 +191,7 @@ # wasted by previous incorrect answers. return 'invalidhc'; } - if ($form->{hcanswer} && $form->{hcanswer} eq $answer) { + if ($form->{hcanswer} && lc($form->{hcanswer}) eq lc($answer)) { # Correct answer submitted. return 'ok'; } Index: slashjp/plugins/HumanConf/INSTALL-NOTES diff -u slashjp/plugins/HumanConf/INSTALL-NOTES:1.1.1.1 slashjp/plugins/HumanConf/INSTALL-NOTES:1.2 --- slashjp/plugins/HumanConf/INSTALL-NOTES:1.1.1.1 Wed Jan 28 06:54:58 2004 +++ slashjp/plugins/HumanConf/INSTALL-NOTES Wed Jul 12 20:41:49 2006 @@ -14,7 +14,7 @@ If you're on Debian, install these packages: - libfreetype6 libfreetype6-dev freetype2 + libfreetype6 libfreetype6-dev libttf2 libjpeg62 libjpeg62-dev libgd2-xpm libgd2-xpm-dev libgd-tools @@ -33,7 +33,7 @@ install GD GD::Text GD::Text::Align -You'll be asked about whether you want to build it with JPEG, FreeType and +You may be asked about whether you want to build it with JPEG, FreeType and XPM support; answer yes, yes, and I don't think XPM matters either way. If you have compile problems during the make, check which version of libgd you have installed and compare against the library version that the perl Index: slashjp/plugins/HumanConf/PLUGIN diff -u slashjp/plugins/HumanConf/PLUGIN:1.2 slashjp/plugins/HumanConf/PLUGIN:1.3 --- slashjp/plugins/HumanConf/PLUGIN:1.2 Fri Dec 24 05:13:37 2004 +++ slashjp/plugins/HumanConf/PLUGIN Wed Jul 12 20:41:49 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:37 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:49 sugi Exp $ name=HumanConf description="Human Confirmation" mysql_dump=mysql_dump Index: slashjp/plugins/HumanConf/hc_maintain_pool.pl diff -u slashjp/plugins/HumanConf/hc_maintain_pool.pl:1.2 slashjp/plugins/HumanConf/hc_maintain_pool.pl:1.3 --- slashjp/plugins/HumanConf/hc_maintain_pool.pl:1.2 Fri Dec 24 05:13:37 2004 +++ slashjp/plugins/HumanConf/hc_maintain_pool.pl Wed Jul 12 20:41:49 2006 @@ -1,13 +1,13 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: hc_maintain_pool.pl,v 1.2 2004/12/23 20:13:37 oliver Exp $ +# $Id: hc_maintain_pool.pl,v 1.3 2006/07/12 11:41:49 sugi Exp $ use strict; use Slash::Utility; -use vars qw( %task $me ); +use vars qw( %task $me $task_exit_flag ); $task{$me}{timespec} = '10,40 * * * *'; $task{$me}{timespec_panic_1} = ''; @@ -24,6 +24,7 @@ my($deleted, $inserted, $cursize, $hcoff) = (0, 0, 0, ''); if ($constants->{hc}) { $deleted = $humanconf->deleteOldFromPool() || 0; + return "del $deleted, aborted after deleteOldFromPool" if $task_exit_flag; $inserted = $humanconf->fillPool() || 0; $cursize = $humanconf->getPoolSize() || 0; } else { Index: slashjp/plugins/HumanConf/mysql_dump diff -u slashjp/plugins/HumanConf/mysql_dump:1.3 slashjp/plugins/HumanConf/mysql_dump:1.4 --- slashjp/plugins/HumanConf/mysql_dump:1.3 Fri Dec 31 21:36:48 2004 +++ slashjp/plugins/HumanConf/mysql_dump Wed Jul 12 20:41:49 2006 @@ -1,23 +1,29 @@ # -# $Id: mysql_dump,v 1.3 2004/12/31 12:36:48 oliver Exp $ +# $Id: mysql_dump,v 1.4 2006/07/12 11:41:49 sugi Exp $ # INSERT INTO humanconf_questions (hcqid, filedir, urlprefix, question) VALUES (1, '/usr/local/slash/site/www.example.com/htdocs/images/hc', 'http://www.example.com/images/hc', 'To confirm you\'re not a script,
please type the text shown in this image:'); INSERT INTO vars (name, value, description) VALUES ('hc', '0', 'HumanConf master switch, 0=off, 1=on'); +INSERT INTO vars (name, value, description) VALUES ('hc_fontpath', '/usr/share/fonts/truetype', 'GD::Text font_path'); INSERT INTO vars (name, value, description) VALUES ('hc_formname_regex', '^(?:comments|(?:login|users)/(?:nu|mp))$', 'Formnames which (may) require HumanConf'); INSERT INTO vars (name, value, description) VALUES ('hc_maxkarma', '25', 'Maximum karma at which users need HumanConf (beyond this we assume they are human) - set large negative to exempt all logged-in users, set large positive if all users must comply'); -INSERT INTO vars (name, value, description) VALUES ('hc_q1_prefnumpixels', '1000', 'For question 1 (images), preferred number of pixels'); +INSERT INTO vars (name, value, description) VALUES ('hc_q1_lettersomit', 'hlou', 'For question 1 (images), which letters should never appear?'); +INSERT INTO vars (name, value, description) VALUES ('hc_q1_linethick', '2', 'For question 1 (images), thickness of the lines that are drawn to confuse OCR'); +INSERT INTO vars (name, value, description) VALUES ('hc_q1_linecloseness', '8', 'For question 1 (images), closeness of the lines drawn over the letters, higher means more density'); INSERT INTO vars (name, value, description) VALUES ('hc_q1_margin', '6', 'For question 1 (images), margin around the image in pixels'); INSERT INTO vars (name, value, description) VALUES ('hc_q1_maxrad', '0.2', 'For question 1 (images), maximum number of radians to rotate (positive or negative, so the range is twice this)'); INSERT INTO vars (name, value, description) VALUES ('hc_q1_numchars', '3', 'For question 1 (images), number of chars of text in the answer'); -INSERT INTO vars (name, value, description) VALUES ('hc_fontpath', '/usr/share/fonts/truetype', 'GD::Text font_path'); +INSERT INTO vars (name, value, description) VALUES ('hc_q1_prefnumpixels', '1000', 'For question 1 (images), preferred number of pixels'); +INSERT INTO vars (name, value, description) VALUES ('hc_q1_usedict', '', 'For question 1 (images), use words from a dictionary? if blank, no; otherwise, value is the absolute path to the newline-delimited file e.g. /usr/dict/words and hc_q1_lettersomit is ignored'); +INSERT INTO vars (name, value, description) VALUES ('hc_q1_usedict_excl', 'shiny$ metal ^daffodil', 'If hc_q1_usedict is set, space-sep list of regexes to exclude from words to use'); INSERT INTO vars (name, value, description) VALUES ('hc_poolsize', '20000', 'Number of entries desired for the HumanConf pool'); INSERT INTO vars (name, value, description) VALUES ('hc_poolmaxfill', '2000', 'Number of entries at a time to fill the pool with'); INSERT INTO vars (name, value, description) VALUES ('hc_pool_secs_before_del', '21600', 'Number of seconds after a pool entry last used before it will be deleted'); INSERT INTO vars (name, value, description) VALUES ('hc_pool_secs_before_use', '10', 'Number of seconds after a pool entry created before it will be used'); INSERT INTO vars (name, value, description) VALUES ('hc_possible_fonts', '', 'Possible fonts to use (space-separated, empty for the default)'); -INSERT INTO vars (name, value, description) VALUES ('hc_sw_comments', '0', 'HumanConf switch for posting comments'); +INSERT INTO vars (name, value, description) VALUES ('hc_sw_comments', '0', 'HumanConf switch for posting comments: 0=off, 1=anon only, 2=also logged-in with low karma'); INSERT INTO vars (name, value, description) VALUES ('hc_sw_mailpasswd', '1', 'HumanConf switch for mailing a password'); INSERT INTO vars (name, value, description) VALUES ('hc_sw_newuser', '1', 'HumanConf switch for creating a new user'); INSERT INTO vars (name, value, description) VALUES ('hc_image_format','jpeg','Format for HC images (png, jpeg, etc.)'); + Index: slashjp/plugins/HumanConf/mysql_schema diff -u slashjp/plugins/HumanConf/mysql_schema:1.2 slashjp/plugins/HumanConf/mysql_schema:1.3 --- slashjp/plugins/HumanConf/mysql_schema:1.2 Fri Dec 24 05:13:37 2004 +++ slashjp/plugins/HumanConf/mysql_schema Wed Jul 12 20:41:49 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema,v 1.2 2004/12/23 20:13:37 oliver Exp $ +# $Id: mysql_schema,v 1.3 2006/07/12 11:41:49 sugi Exp $ # DROP TABLE IF EXISTS humanconf; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:49 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:49 +0900 Subject: [Slashdotjp-dev 443] CVS update: slashjp/plugins/HumanConf/templates Message-ID: <20060712114149.D741B2AC0EB@users.sourceforge.jp> Index: slashjp/plugins/HumanConf/templates/data;humanconf;default diff -u slashjp/plugins/HumanConf/templates/data;humanconf;default:1.2 slashjp/plugins/HumanConf/templates/data;humanconf;default:1.3 --- slashjp/plugins/HumanConf/templates/data;humanconf;default:1.2 Fri Dec 24 05:13:38 2004 +++ slashjp/plugins/HumanConf/templates/data;humanconf;default Wed Jul 12 20:41:49 2006 @@ -15,16 +15,16 @@ [% CASE 'nomorechances' %] [% returnme.data_constant = 1 %] - Sorry, you failed to prove your humanity. To try again, - you have to start over. + Sorry, you failed to prove your humanity. To try again, + you have to start over. [% CASE 'imgalttext' %] [% returnme.data_constant = 1 %] - [% "random letters - if you are visually impaired, please email us at " + [% "verification text - if you are visually impaired, please email us at " _ constants.adminmail | strip_attribute %] [% END %] __seclev__ 500 __version__ -$Id: data;humanconf;default,v 1.2 2004/12/23 20:13:38 oliver Exp $ +$Id: data;humanconf;default,v 1.3 2006/07/12 11:41:49 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:49 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:49 +0900 Subject: [Slashdotjp-dev 444] CVS update: slashjp/plugins/HumanConf/Static Message-ID: <20060712114149.B55A22AC106@users.sourceforge.jp> Index: slashjp/plugins/HumanConf/Static/Static.pm diff -u slashjp/plugins/HumanConf/Static/Static.pm:1.3 slashjp/plugins/HumanConf/Static/Static.pm:1.4 --- slashjp/plugins/HumanConf/Static/Static.pm:1.3 Fri Dec 31 21:36:49 2004 +++ slashjp/plugins/HumanConf/Static/Static.pm Wed Jul 12 20:41:49 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Static.pm,v 1.3 2004/12/31 12:36:49 oliver Exp $ +# $Id: Static.pm,v 1.4 2006/07/12 11:41:49 sugi Exp $ package Slash::HumanConf::Static; @@ -18,7 +18,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -35,30 +35,11 @@ $self->{imagemargin} = $constants->{hc_q1_margin} || 6; - # Use a bit of randomness and fallback to find a font we like. - my @possible_fonts = @{$constants->{hc_possible_fonts}}; - @possible_fonts = ( gdMediumBoldFont, gdLargeFont, gdGiantFont ) if !@possible_fonts; - @possible_fonts = sort { int(rand(3))-1 } @possible_fonts; - - $self->{prefnumpixels} = $constants->{hc_q1_prefnumpixels} || 1000; - my $gdtext = new GD::Text(); - $gdtext->font_path($constants->{hc_fontpath} || '/usr/share/fonts/truetype'); - $gdtext->set_text($self->shortRandText()); - my $smallest_diff = 2**31; - for my $font (@possible_fonts) { - @{$self->{set_font_args}} = ( $font ); - if ($font =~ m{^(\w+)/(\d+)$}) { - @{$self->{set_font_args}} = ($1, $2); - } - $gdtext->set_font(@{$self->{set_font_args}}); - my($tempw, $temph) = ($gdtext->get("width"), $gdtext->get("height")); - my $pixels = ($tempw+$self->{imagemargin}) * ($temph+$self->{imagemargin}); - my $diff = $pixels - $self->{prefnumpixels}; - $diff = -$diff if $diff < 0; - if ($diff < $smallest_diff) { - $self->{font} = $font; - $smallest_diff = $diff; - } + # Set the list of possible fonts. + if ($constants->{hc_possible_fonts} && @{$constants->{hc_possible_fonts}}) { + @{ $self->{possible_fonts} } = @{$constants->{hc_possible_fonts}}; + } else { + @{ $self->{possible_fonts} } = ( gdMediumBoldFont, gdLargeFont, gdGiantFont ); } return $self; @@ -112,7 +93,10 @@ my $delrows = 0; my $loop_num = 1; my $remaining_to_delete = $want_delete; + my $successfully_deleted = 0; my $secs = $constants->{hc_pool_secs_before_del} || 21600; + my $lastused_max_secs = $secs * 2; + $lastused_max_secs = 86400*3 if $lastused_max_secs < 86400*3; my $q_hr = $self->sqlSelectAllHashref( "hcqid", "hcqid, filedir", @@ -136,7 +120,7 @@ "humanconf_pool", { inuse => 2, -lastused => "lastused" }, "lastused < DATE_SUB(NOW(), INTERVAL $secs SECOND) - AND inuse = 0 + AND (inuse = 0 OR lastused < DATE_SUB(NOW(), INTERVAL $lastused_max_secs SECOND)) $hcpid_clause" ); next if !$rows; @@ -192,17 +176,9 @@ "humanconf_pool", "hcpid IN ($hcpids_list)" ); - if ($new_delrows != $remaining_to_delete) { - warn "HumanConf warning: deleted number" - . " of rows '$new_delrows'" - . " not equal to attempted number to delete" - . " '$remaining_to_delete'"; - } + $successfully_deleted += $new_delrows; $remaining_to_delete -= $new_delrows; $delrows += $new_delrows; - } else { - warn "HumanConf warning: no rows to delete; attempted" - . " '$remaining_to_delete'"; } # Pass 5: @@ -216,6 +192,10 @@ ++$loop_num; } + + if ($loop_num > 2) { + warn scalar(gmtime) . " hc_maintain_pool.pl deleteOldFromPool looped $loop_num times, deleted $successfully_deleted of $want_delete"; + } # Return the number of rows successfully deleted. This # should also be the number of files deleted. @@ -285,11 +265,11 @@ # (Collisions should only occur one time in a zillion, but # it's always a good idea to check.) my $encoded_name = $self->encode_hcpid($hcpid + $randomfactor); - $filename = sprintf("%02d/%s$extension", $hcpid%100, $encoded_name); + $filename = sprintf("%02d/%s%s", $hcpid % 100, $encoded_name, $extension); $full_filename = "$dir/$filename"; if (-e $full_filename) { $filename = ""; - $randomfactor = rand(1000); + $randomfactor = int(rand(1000)); } } my $full_dir = $full_filename; @@ -332,6 +312,155 @@ }, "hcpid=$hcpid"); } +sub get_sizediff { + my($self, $gdtext, $pixels_wanted, $font, $fontsize) = @_; + $gdtext->set_font($font, $fontsize); + my($tempw, $temph) = ($gdtext->get("width"), $gdtext->get("height")); + my $pixels = ($tempw+$self->{imagemargin}) * ($temph+$self->{imagemargin}); + my $diff = abs($pixels - $pixels_wanted); + return $diff; +} + +sub get_new_gdtext { + my($self, $text) = @_; + my $constants = getCurrentStatic(); + + my $gdtext = new GD::Text(); + $gdtext->font_path($constants->{hc_fontpath} || '/usr/share/fonts/truetype'); + $gdtext->set_text($text); + + return $gdtext; +} + +sub get_font_args { + my($self, $text) = @_; + my $constants = getCurrentStatic(); + + my $gdtext = $self->get_new_gdtext($text); + + $self->{prefnumpixels} = $constants->{hc_q1_prefnumpixels} || 1000; + + my @pf = @{ $self->{possible_fonts} }; + my $font = @pf[rand @pf] || ''; + my $first_fontsize_try = 30; # default first guess + if ( $font =~ m{^(\w+)/(\d+)$} ) { + $font = $1; + $first_fontsize_try = $2; + } + + # "pixels wanted" + my $pw = $self->{prefnumpixels}; + + # We are looking for the minimum of the pixel difference. Since + # image size increases monotonically with font size, there is + # guaranteed to be exactly 1 or 2 values at which the pixel diff + # is at a minimum. We begin with one guess, then check the + # diffs immediately above and below it to see which is headed in + # the right direction. + my $i = $first_fontsize_try - 1; + my $j = $first_fontsize_try; # first guess + my $k = $first_fontsize_try + 1; + my $di = $self->get_sizediff($gdtext, $pw, $font, $i); + my $dj = $self->get_sizediff($gdtext, $pw, $font, $j); + my $dk = $self->get_sizediff($gdtext, $pw, $font, $k); + if ($di == $dj || $dj == $dk) { + # Two values being equal means that they are both the + # minimum, so we can return either one. We got lucky! + return ($font, $j); + } + if ($di > $dj && $dj < $dk) { + # The center value being smaller than the other two + # means that it is the one minimum. We got lucky! + return ($font, $j); + } + + # Either i or k is a better choice than j. Figure out which, + # then set up the vars so we walk up or down sizes starting + # from there. + my @vals = ( $j ); + my $start = $j; + my $multiplier; + if ($di < $dj) { + # i is a better direction, so we walk down. + $multiplier = 5/6; + push @vals, $i; + } else { + # k is a better direction, so we walk up. + $multiplier = 6/5; + push @vals, $k; + } + + # Walk up or down until we bridge the minimum. We'll know + # that happens when we find a value that _increases_ from + # the minimum seen so far. We want to save the last 3 + # values found, at that point. + my $min_so_far = $dj; + my $best_size = $j; + my $found_min = 0; + my $next_try = $start; + my($fontsize_smallest, $fontsize_largest) = (5, 100); + while (!$found_min) { + my $old_try = $next_try; + $next_try = int($old_try * $multiplier + 0.5); + if ($next_try == $old_try) { + # Must change by at least one point size + if ($multiplier < 1) { + $next_try = $old_try - 1; + } else { + $next_try = $old_try + 1; + } + } + push @vals, $next_try; + my $new_d = $self->get_sizediff($gdtext, $pw, $font, $next_try); + if ($new_d < $min_so_far) { + # That beats the old record. + $min_so_far = $new_d; + $best_size = $next_try; + } else { + # OK, we've crossed the minimum and come back up. + $found_min = 1; + } + if ($next_try < $fontsize_smallest || $next_try > $fontsize_largest) { + # We're out of bounds, that's bad. + $found_min = 1; + print STDERR scalar(gmtime) . " Font size out of bounds: $font $next_try $new_d\n"; + } + } + + # The answer we want is somewhere in the range of the last + # 3 values we checked. + my($left, $right); + if ($multiplier < 1) { + $left = $vals[-1]; + $right = $vals[-3]; + } else { + $left = $vals[-3]; + $right = $vals[-1]; + } +#print STDERR "font=$font left=$left right=$right vals=@vals\n"; + + # Hopefully this is a narrow range so we can just check values + # within it to find the answer we want. (This could be better + # optimized, but at this point, image generation happens very + # quickly, so I'm satisfied so far.) + $min_so_far = 2**31 - 1; + $best_size = undef; + DO_TRY: for $next_try ($left .. $right) { + my $new_d = $self->get_sizediff($gdtext, $pw, $font, $next_try); + if ($new_d < $min_so_far) { + $min_so_far = $new_d; + $best_size = $next_try; + } else { +#print STDERR "font=$font next_try=$next_try new_d=$new_d min_so_far=$min_so_far done\n"; + # We've just gone past the minimum, we're done. + last DO_TRY; + } +#print STDERR "font=$font next_try=$next_try new_d=$new_d min_so_far=$min_so_far best_size=$best_size\n"; + } + + return($font, $best_size); +} + sub drawImage { my($self) = @_; my $constants = getCurrentStatic(); @@ -347,13 +476,13 @@ # Set up the text object (this could probably be cached in $self, # but it hardly takes any time to do it over and over). - my $gdtext = new GD::Text(); - $gdtext->font_path($constants->{hc_fontpath} || '/usr/share/fonts/truetype'); + my $answer = $self->shortRandText(); + my @font_args = $self->get_font_args($answer); + my $gdtext = $self->get_new_gdtext($answer); + $gdtext->set_font(@font_args); - # Set up the text, and set up the image. - my $answer = shortRandText(); - $gdtext->set_text($answer); - $gdtext->set_font(@{$self->{set_font_args}}); + # Based on the font size for this word, and the resulting size + # of the drawn text, set up the image object. my($width, $height) = ($gdtext->get("width")+$self->{imagemargin}, $gdtext->get("height")+$self->{imagemargin}); my $image = new GD::Image($width, $height); @@ -376,10 +505,15 @@ # Paint the white background. $image->filledRectangle(0, 0, $width, $height, $background); + if ($image->can('setThickness')) { + # I don't think GD prior to 2.07 has setThickness(). + $image->setThickness($constants->{hc_q1_linethick} || 1); + } my $poly = new GD::Polygon; if ($width+$height > 100) { # Draw a grid of lines on the image, same color as the text. - my $pixels_between = ($width+$height)/8; + my $lc = $constants->{hc_q1_linecloseness} || 8; + my $pixels_between = ($width+$height)/$lc; $pixels_between = 20 if $pixels_between < 20; my $offset = int(rand($pixels_between)); my $x = int(rand($pixels_between)); @@ -425,17 +559,53 @@ $image->setPixel($px, $py, @dotcolor[rand($n_dotcolors)]); } - # Superimpose the text over the random stuff. - my $gdtextalign = new GD::Text::Align( + # Set up an alignment box so we can determine where to put the + # text on the image. + my $gdtextalign_bbox = new GD::Text::Align( $image, - halign=>"center", valign=>"center", - color => $textcolor + halign => 'center', valign => 'center', + text => $answer, ); - $gdtextalign->set(text => $gdtext->get("text")); - $gdtextalign->set_font($gdtext->get("font") , $gdtext->get("ptsize")); + $gdtextalign_bbox->set_font(@font_args); + my($center_x, $center_y) = (int($width/2), int($height/2)); + # Pick an angle between $max_angle/4 and $max_angle, randomly + # positive or negative. my $max_angle = $constants->{hc_q1_maxrad} || 0.2; - my $angle = (rand(1)*2-1) * $max_angle; - $gdtextalign->draw(int($width/2), int($height/2), $angle); + my $angle = (rand(1)*0.75)*$max_angle + $max_angle/4; + $angle *= -1 if rand(1) < 0.5; + # The variable names stand for lower left x coordinate, etc. + my($ll_x, $ll_y, $lr_x, $lr_y, $ur_x, $ur_y, $ul_x, $ul_y) = + $gdtextalign_bbox->bounding_box($center_x, $center_y, 0); +#print STDERR "aligned $answer center=$center_x, $center_y angle=$angle bb: $ll_x, $ll_y, $lr_x, $lr_y, $ur_x, $ur_y, $ul_x, $ul_y\n"; + + # We're done with the alignment box now. Place the text on the + # image according to the bounding box. Split the string into a + # left and right half and draw them separately. + my $string_break = int(rand(length($answer)-2))+1; + my $answer_left = substr($answer, 0, $string_break); + my $angle_left = $angle; + my $gdtextalign_left = new GD::Text::Align( + $image, + halign => 'left', valign => 'center', + colour => $textcolor, # apparently Australians prefer a 'u' + text => $answer_left, + ); + $gdtextalign_left->set_font(@font_args); + my $cl_y = int(($ll_y+$ul_y)/2); + my @bb = $gdtextalign_left->draw(int($ul_x), $cl_y, $angle); +#printf STDERR "gdta_left drew left-top $answer_left at ul_x=$ul_x,cl_y=$cl_y angle=%.4f, bb: @bb\n", $angle; + my $answer_right = substr($answer, $string_break); + my $angle_right = rand(1) < 0.5 ? $angle : -$angle; + my $gdtextalign_right = new GD::Text::Align( + $image, + halign => 'right', valign => 'center', + colour => $textcolor, # apparently Australians prefer a 'u' + text => $answer_right, + ); + $gdtextalign_right->set_font(@font_args); + my $cr_y = int(($lr_y+$ur_y)/2); + @bb = $gdtextalign_right->draw(int($lr_x), $cr_y, $angle_right); +#printf STDERR "gdta_right drew right-bottom $answer_right at lr_x=$lr_x,cr_y$cr_y angle=%.4f, bb: @bb\n", $angle; return($answer, $image); } @@ -443,19 +613,36 @@ sub shortRandText { my($self) = @_; my $constants = getCurrentStatic(); - my $num_chars = $constants->{hc_q1_numchars} || 3; - my @c = ('a'..'g', 'i'..'k', - # Noel, Noel - # (we don't use letters that could be confused - # with numbers or other letters) - 'm', 'n', 'p'..'t', 'v'..'z'); + my $text = ""; + if ($constants->{hc_q1_usedict} && $constants->{hc_q1_numchars} > 2) { + $text = $self->shortRandText_dict(); + } + return $text if $text; + + my $omit = $constants->{hc_q1_lettersomit} || 'hlou'; + my $omit_regex = qr{[^$omit]}; + my $num_chars = $constants->{hc_q1_numchars} || 3; + my @c = grep /$omit_regex/, ('a' .. 'z'); while (!$text) { for (1..$num_chars) { $text .= $c[rand(@c)]; } } - $text; + return $text; +} + +sub shortRandText_dict { + my $constants = getCurrentStatic(); + my $filename = $constants->{hc_q1_usedict}; + return "" if !$filename || !-r $filename; + my $options = { + min_chars => $constants->{hc_q1_numchars} - 1, + max_chars => $constants->{hc_q1_numchars} + 1, + excl_regexes => [ split / /, ($constants->{hc_q1_usedict_excl} || "") ], + }; + $options->{min_chars} = 3 if $options->{min_chars} < 3; + return getRandomWordFromDictFile($filename, $options); } # To prevent attackers from pulling down all the images and manually From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:48 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:48 +0900 Subject: [Slashdotjp-dev 445] CVS update: slashjp/plugins/FAQSlashdot Message-ID: <20060712114148.CF5542AC101@users.sourceforge.jp> Index: slashjp/plugins/FAQSlashdot/PLUGIN diff -u slashjp/plugins/FAQSlashdot/PLUGIN:1.3 slashjp/plugins/FAQSlashdot/PLUGIN:1.4 --- slashjp/plugins/FAQSlashdot/PLUGIN:1.3 Fri Dec 31 21:36:47 2004 +++ slashjp/plugins/FAQSlashdot/PLUGIN Wed Jul 12 20:41:48 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.3 2004/12/31 12:36:47 oliver Exp $ +# $Id: PLUGIN,v 1.4 2006/07/12 11:41:48 sugi Exp $ name=FAQSlashdot description="Slashdot FAQ" htdoc_faq=faq/UI.shtml @@ -7,6 +7,7 @@ htdoc_faq=faq/com-mod.shtml htdoc_faq=faq/editorial.shtml htdoc_faq=faq/faq-meta.shtml +htdoc_faq=faq/feeds.shtml htdoc_faq=faq/friends.shtml htdoc_faq=faq/index.shtml htdoc_faq=faq/interviews.shtml @@ -15,6 +16,7 @@ htdoc_faq=faq/subscriptions.shtml htdoc_faq=faq/suggestions.shtml htdoc_faq=faq/tech.shtml +htdoc_faq=faq/tags.shtml image_faq=images/faq/foe.gif image_faq=images/faq/friend.gif image_faq=images/faq/neutral.gif From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:50 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:50 +0900 Subject: [Slashdotjp-dev 446] CVS update: slashjp/plugins/Login Message-ID: <20060712114150.963672AC0EB@users.sourceforge.jp> Index: slashjp/plugins/Login/PLUGIN diff -u slashjp/plugins/Login/PLUGIN:1.1 slashjp/plugins/Login/PLUGIN:1.2 --- slashjp/plugins/Login/PLUGIN:1.1 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/PLUGIN Wed Jul 12 20:41:50 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.1 2004/12/31 12:36:50 oliver Exp $ +# $Id: PLUGIN,v 1.2 2006/07/12 11:41:50 sugi Exp $ name=Login description="Login system for users" htdoc=login.pl Index: slashjp/plugins/Login/login.pl diff -u slashjp/plugins/Login/login.pl:1.2 slashjp/plugins/Login/login.pl:1.3 --- slashjp/plugins/Login/login.pl:1.2 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/login.pl Wed Jul 12 20:41:50 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: login.pl,v 1.2 2004/12/31 12:36:50 oliver Exp $ +# $Id: login.pl,v 1.3 2006/07/12 11:41:50 sugi Exp $ use strict; use Slash 2.003; @@ -12,7 +12,7 @@ use Slash::XML; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; sub main { my $slashdb = getCurrentDB(); @@ -91,8 +91,8 @@ $error = 1; } elsif ($matchname ne '' && $form->{newusernick} ne '') { if ($constants->{newuser_portscan}) { - my $is_trusted = $slashdb->checkIsTrusted($user->{ipid}); - if ($is_trusted ne 'yes') { + my $is_trusted = $slashdb->checkAL2($user->{srcids}, 'trusted'); + if (!$is_trusted) { my $is_proxy = $slashdb->checkForOpenProxy($user->{hostip}); if ($is_proxy) { push @note, getData('new_user_open_proxy', { @@ -216,7 +216,19 @@ my $user_send = $reader->getUser($uid); if (!$error) { - if ($reader->checkReadOnly(nopost => { ipid => $user->{ipid} })) { + # A user coming from a srcid that's been marked as not + # acceptable for posting from also does not get to + # mail a password to anyone. + + ## XXX: we added uid to srcids, so now this is broken; + ## anywhere else we need to address this? + my %srcids; + @srcids{keys %{$user->{srcids}}} = values %{$user->{srcids}}; + delete $srcids{uid}; + + if ($reader->checkAL2(\%srcids, 'nopost') + || $reader->checkAL2(\%srcids, 'nopostanon') + ) { push @note, getData('mail_readonly'); $error = 1; @@ -242,7 +254,7 @@ my $uid = $user_send->{uid}; my $newpasswd = $slashdb->getNewPasswd($uid); - my $tempnick = fixparam($user_send->{nickname}); + my $tempnick = $user_send->{nickname}; my $subject = getData('mail_subject', { nickname => $user_send->{nickname} }); # Pull out some data passed in with the request. Only the IP @@ -355,7 +367,6 @@ $slashdb->setUser($user->{uid}, $user_save); $note = getData('passchanged'); - my $value = $slashdb->getLogToken($uid, 1); my $cookie = bakeUserCookie($uid, $slashdb->getLogToken($uid, 1)); setCookie('user', $cookie, $user_save->{session_login}); } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:49 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:49 +0900 Subject: [Slashdotjp-dev 447] CVS update: slashjp/plugins/Hof/templates Message-ID: <20060712114149.5CD262AC104@users.sourceforge.jp> Index: slashjp/plugins/Hof/templates/data;hof;default diff -u slashjp/plugins/Hof/templates/data;hof;default:1.1.1.1 slashjp/plugins/Hof/templates/data;hof;default:1.2 --- slashjp/plugins/Hof/templates/data;hof;default:1.1.1.1 Wed Jan 28 06:54:57 2004 +++ slashjp/plugins/Hof/templates/data;hof;default Wed Jul 12 20:41:49 2006 @@ -26,4 +26,4 @@ __seclev__ 10000 __version__ -$Id: data;hof;default,v 1.1.1.1 2004/01/27 21:54:57 oliver Exp $ +$Id: data;hof;default,v 1.2 2006/07/12 11:41:49 sugi Exp $ Index: slashjp/plugins/Hof/templates/main;hof;default diff -u slashjp/plugins/Hof/templates/main;hof;default:1.2 slashjp/plugins/Hof/templates/main;hof;default:1.3 --- slashjp/plugins/Hof/templates/main;hof;default:1.2 Fri Dec 31 21:36:48 2004 +++ slashjp/plugins/Hof/templates/main;hof;default Wed Jul 12 20:41:49 2006 @@ -18,54 +18,53 @@ __name__ main __template__ -[% USE Slash %] -

[% PROCESS titlebar title => 'Most Active Stories' %] +

[% PROCESS titlebar title => 'Most Active Stories' %] [% FOREACH item = actives %] -[% item.3 %] +[% item.3 %] [% storylinks = Slash.linkStory({ link => item.1, section => item.2, sid => item.0 }) %] -[% storylinks.1 %] -by [% item.4 %]
-[% END %]

+[% storylinks.1 %] +by [% item.4 %]
+[% END %]

-

[% PROCESS titlebar title => 'Most Visited Stories' %] +

[% PROCESS titlebar title => 'Most Visited Stories' %] [% FOREACH item = visited %] -[% item.3 %] +[% item.3 %] [% storylinks = Slash.linkStory({ link => item.1, section => item.2, sid => item.0 }) %] -[% storylinks.1 %] -by [% item.4 %]
-[% END %]

+[% storylinks.1 %] +by [% item.4 %]
+[% END %]

-

[% PROCESS titlebar title => 'Most Active Authors' %] +

[% PROCESS titlebar title => 'Most Active Authors' %] [% FOREACH item = activea %] -[% item.0 %] [% item.1 %]
-[% END %]

+[% item.0 %] [% IF item.2 %][% END %][% item.1 %][% IF item.2 %][% END %]
+[% END %]

-

[% PROCESS titlebar title => 'Most Active Submitters' %] +

[% PROCESS titlebar title => 'Most Active Submitters' %] [% FOREACH item = activesub %] -[% item.0 %] [% item.1 %]
-[% END %]

+[% item.0 %] [% item.1 %]
+[% END %]

-

[% PROCESS titlebar title => 'Most Active Poll Topics' %] +

[% PROCESS titlebar title => 'Most Active Poll Topics' %] [% FOREACH item = activep %] -[% item.0 %] [% item.1 %]
-[% END %]

+[% item.0 %] [% item.1 %]
+[% END %]

[% IF topcomments.size > 0 %] -

[% PROCESS titlebar title => 'Top 10 Comments' %] +

[% PROCESS titlebar title => 'Top 10 Comments' %] [% FOREACH top = topcomments %] -[% top.score %] - [% top.subj %] - by [% top.nickname | strip_literal %] on [% top.cdate %]
- - attached to [% storylinks = Slash.linkStory({ link => top.title, section => top.section, sid => top.sid }) %] -[% storylinks.1 %] - posted on [% top.sdate %] by [% top.anickname %]

-[% END %]

+[% top.score %] + [% top.subj %] + by [% top.nickname | strip_literal %] on [% top.cdate %]
+ + attached to [% storylinks = Slash.linkStory({ link => top.title, section => top.section, sid => top.sid }) %] +[% storylinks.1 %] + posted on [% top.sdate %] by [% top.anickname %]

+[% END %]

[% END %] -

generated on [% currtime %]

+

generated on [% currtime %]

__seclev__ 10000 __version__ -$Id: main;hof;default,v 1.2 2004/12/31 12:36:48 oliver Exp $ +$Id: main;hof;default,v 1.3 2006/07/12 11:41:49 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:51 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:51 +0900 Subject: [Slashdotjp-dev 448] CVS update: slashjp/plugins/Messages Message-ID: <20060712114151.092EB2AC0EB@users.sourceforge.jp> Index: slashjp/plugins/Messages/Messages.pm diff -u slashjp/plugins/Messages/Messages.pm:1.3 slashjp/plugins/Messages/Messages.pm:1.4 --- slashjp/plugins/Messages/Messages.pm:1.3 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Messages/Messages.pm Wed Jul 12 20:41:50 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Messages.pm,v 1.3 2004/12/31 12:36:50 oliver Exp $ +# $Id: Messages.pm,v 1.4 2006/07/12 11:41:50 sugi Exp $ package Slash::Messages; @@ -41,7 +41,7 @@ use Slash::Display; use Slash::Utility; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; #======================================================================== @@ -59,7 +59,7 @@ =item TO_ID The UID of the user the message is sent to. Must match a valid -uid in the users table. +uid in the users table. Can be an arrayref of UIDs. =item TYPE @@ -95,7 +95,7 @@ =item Return value -The created message's "id" in the message_drop table. +The created message's "id" (or multiple ids) in the message_drop table. =item Dependencies @@ -122,19 +122,30 @@ return 0; } + $uid = [$uid] unless ref $uid; + my @users; + if (!$altto) { # check for $uid existence - my $slashdb = getCurrentDB(); - unless ($slashdb->getUser($uid)) { - messagedLog(getData("user not found", { uid => $uid }, "messages")); - return 0; + my $reader = getObject('Slash::Journal', { db_type => 'reader' }); + for my $u (@$uid) { + if ($reader->existsUid($u)) { + push @users, $u; + } else { + messagedLog(getData("user not found", { uid => $u }, "messages")); + } } } else { - if (!defined($uid) || $uid =~ /\D/) { - $uid = 0; + for my $u (@$uid) { + if (!defined($uid) || $uid =~ /\D/) { + $u = 0; + } + push @users, $u; } } + return 0 unless @users; + if (!ref $data) { $message = $data; } elsif (ref $data eq 'HASH') { @@ -183,10 +194,15 @@ return 0; } - my($msg_id) = $self->_create($uid, $code, $message, $fid, $altto, $send); - return $msg_id; + my @msg_ids; + for my $u (@users) { + my($msg_id) = $self->_create($u, $code, $message, $fid, $altto, $send); + push @msg_ids, $msg_id if $msg_id; + } + return @msg_ids > 1 ? @msg_ids : $msg_ids[0]; } + #======================================================================== =head2 create_web(MESSAGE) @@ -500,6 +516,7 @@ my $slashdb = getCurrentDB(); return unless $tuser; + $code = -1 unless defined $code; ($code, my($type)) = $self->getDescription('messagecodes', $code); $code = -1 unless defined $code; @@ -558,7 +575,7 @@ my $subject = $self->callTemplate('msg_email_subj', $msg); if (bulkEmail($addrs, $subject, $content)) { - $self->log($msg, MSG_MODE_EMAIL); + $self->log($msg, MSG_MODE_EMAIL, scalar @$addrs); return 1; } else { messagedLog(getData("send mail error", { @@ -580,7 +597,7 @@ sub getWebByUID { my($self, $uid) = @_; - $uid ||= $ENV{SLASH_USER}; + $uid ||= getCurrentUser('uid'); my $msguser = $self->getUser($uid); my $msgs = $self->_get_web_by_uid($uid) or return 0; @@ -968,10 +985,16 @@ sub getDescription { my($self, $codetype, $key) = @_; +if (!defined($key) || !length($key)) { +my $codetype_str = defined($codetype) ? $codetype : '(undef)'; +my $key_str = defined($key) ? $key : '(undef)'; +print STDERR "Message.pm getDescription called with codetype='$codetype_str' key='$key_str'\n"; +return; +} my $codes = $self->getDescriptions($codetype); - if ($key =~ /^\d+$/) { + if ($key =~ /^-?\d+$/) { unless (exists $codes->{$key}) { return; } @@ -1094,4 +1117,4 @@ =head1 VERSION -$Id: Messages.pm,v 1.3 2004/12/31 12:36:50 oliver Exp $ +$Id: Messages.pm,v 1.4 2006/07/12 11:41:50 sugi Exp $ Index: slashjp/plugins/Messages/PLUGIN diff -u slashjp/plugins/Messages/PLUGIN:1.2 slashjp/plugins/Messages/PLUGIN:1.3 --- slashjp/plugins/Messages/PLUGIN:1.2 Fri Dec 24 05:13:39 2004 +++ slashjp/plugins/Messages/PLUGIN Wed Jul 12 20:41:50 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:39 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:50 sugi Exp $ name=Messages description="Messaging system" mysql_schema=mysql_schema @@ -16,6 +16,8 @@ template=templates/display_prefs;messages;default template=templates/emailsponsor;messages;default template=templates/footer;messages;default +template=templates/html_invalid;misc;default +template=templates/html_invalid_subj;misc;default template=templates/journrep;comments;default template=templates/journrep_subj;comments;default template=templates/journuserboxes;misc;default Index: slashjp/plugins/Messages/dump diff -u slashjp/plugins/Messages/dump:1.3 slashjp/plugins/Messages/dump:1.4 --- slashjp/plugins/Messages/dump:1.3 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Messages/dump Wed Jul 12 20:41:50 2006 @@ -1,5 +1,5 @@ # -# $Id: dump,v 1.3 2004/12/31 12:36:50 oliver Exp $ +# $Id: dump,v 1.4 2006/07/12 11:41:50 sugi Exp $ # INSERT INTO code_param (type, code, name) VALUES ('deliverymodes', -1, 'No Messages'); @@ -24,6 +24,7 @@ INSERT INTO message_codes (code, type, seclev, modes, send, subscribe) VALUES (12, 'Relationship Change', 1, '', 'collective', 1); INSERT INTO message_codes (code, type, seclev, modes, send, subscribe) VALUES (13, 'Bad login attempt warnings', 1, 1, 'now', 0); INSERT INTO message_codes (code, type, seclev, modes, acl) VALUES (14, 'Daily Moderation Stats', 100, 0, 'stats'); +INSERT INTO message_codes (code, type, seclev) VALUES (18, 'Invalid HTML Input', 100); INSERT INTO menus (menu, label, value, seclev, menuorder) VALUES ('messages','Inbox','[% gSkin.rootdir %]/my/inbox',1,13); INSERT INTO menus (menu, label, value, seclev, menuorder) VALUES ('messages','Message Preferences','[% gSkin.rootdir %]/my/messages',1,2); Index: slashjp/plugins/Messages/message_delete.pl diff -u slashjp/plugins/Messages/message_delete.pl:1.2 slashjp/plugins/Messages/message_delete.pl:1.3 --- slashjp/plugins/Messages/message_delete.pl:1.2 Fri Dec 24 05:13:39 2004 +++ slashjp/plugins/Messages/message_delete.pl Wed Jul 12 20:41:50 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: message_delete.pl,v 1.2 2004/12/23 20:13:39 oliver Exp $ +# $Id: message_delete.pl,v 1.3 2006/07/12 11:41:50 sugi Exp $ use strict; use File::Spec::Functions; Index: slashjp/plugins/Messages/message_delivery.pl diff -u slashjp/plugins/Messages/message_delivery.pl:1.3 slashjp/plugins/Messages/message_delivery.pl:1.4 --- slashjp/plugins/Messages/message_delivery.pl:1.3 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Messages/message_delivery.pl Wed Jul 12 20:41:50 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: message_delivery.pl,v 1.3 2004/12/31 12:36:50 oliver Exp $ +# $Id: message_delivery.pl,v 1.4 2006/07/12 11:41:50 sugi Exp $ use strict; use File::Spec::Functions; @@ -20,7 +20,8 @@ my($virtual_user, $constants, $slashdb, $user) = @_; my $messages = getObject('Slash::Messages'); - unless ($messages) { + my $messages_reader = getObject('Slash::Messages', { db_type => 'reader' }); + unless ($messages && $messages_reader) { slashdLog("$me: could not instantiate Slash::Messages object"); return; } @@ -39,10 +40,10 @@ my $msgs; if ($constants->{task_options}{all} || $last_deferred ne $now) { - $msgs = $messages->gets(); # do it all, baby + $msgs = $messages_reader->gets(); # do it all, baby $slashdb->setVar('message_last_deferred', $now); } else { - $msgs = $messages->gets($count, { 'send' => 'now' }); + $msgs = $messages_reader->gets($count, { 'send' => 'now' }); } # handle collective msgs @@ -50,7 +51,7 @@ my $c = 0; for my $msg (@$msgs) { my $code = $msg->{code}; - $codes{$code} ||= $messages->getMessageCode($code); + $codes{$code} ||= $messages_reader->getMessageCode($code); if ($codes{$code}{'send'} eq 'collective') { push @{ $collective{ $code }{ $msg->{user}{uid} } }, $msg; $msgs->[$c] = undef; @@ -59,12 +60,12 @@ } for my $code (keys %collective) { - my $type = $messages->getDescription('messagecodes', $code); + my $type = $messages_reader->getDescription('messagecodes', $code); for my $uid (keys %{$collective{ $code }}) { my $coll = $collective{ $code }{ $uid }; my $msg = $coll->[0]; - my $mode = $messages->getMode($msg); + my $mode = $messages_reader->getMode($msg); my $message; # perhaps put these formatting things in templates? Index: slashjp/plugins/Messages/messages.pl diff -u slashjp/plugins/Messages/messages.pl:1.4 slashjp/plugins/Messages/messages.pl:1.5 --- slashjp/plugins/Messages/messages.pl:1.4 Wed Jan 12 18:20:53 2005 +++ slashjp/plugins/Messages/messages.pl Wed Jul 12 20:41:50 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: messages.pl,v 1.4 2005/01/12 09:20:53 oliver Exp $ +# $Id: messages.pl,v 1.5 2006/07/12 11:41:50 sugi Exp $ # this program does some really cool stuff. # so i document it here. yay for me! @@ -12,10 +12,11 @@ use Slash::Constants qw(:web :messages); use Slash::Display; use Slash::Utility; +use Slash::XML; use Time::HiRes; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.5 $ ' =~ /\$Revision:\s+([^\s]+)/; sub main { my $start_time = Time::HiRes::time; @@ -38,6 +39,8 @@ delete_message => [ $user_ok, \&delete_message ], deletemsgs => [ $user_ok, \&delete_messages ], + list_rss => [ !$user->{is_anon}, \&list_messages_rss ], + # send_message => [ $user_ok, \&send_message ], # edit_message => [ !$user->{is_anon}, \&edit_message ], @@ -203,25 +206,26 @@ header(getData('header')) or return; print createMenu('users', { - style => 'tabbed', - justify => 'right', - color => 'colored', - tab_selected => 'preferences', - }); - slashDisplay('prefs_titlebar', { - nickname => $user->{nickname}, - uid => $user->{uid}, - tab_selected => 'messages', - title => getData( 'prefshead' ) + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => 'preferences', }); - print createMenu('messages'); slashDisplay('journuserboxes'); + my $prefs_titlebar = slashDisplay('prefs_titlebar', { + nickname => $user->{nickname}, + uid => $user->{uid}, + tab_selected => 'messages' + }, { Return => 1 }); + my $messages_menu = createMenu('messages'); slashDisplay('display_prefs', { userm => $userm, prefs => $prefs, note => $note, messagecodes => $messagecodes, deliverymodes => $deliverymodes, + prefs_titlebar => $prefs_titlebar, + messages_menu => $messages_menu }); footer(); } @@ -267,29 +271,58 @@ header(getData('header')) or return; # Spank me, this won't be here for long (aka Pater's cleanup will remove it) -Brian print createMenu('users', { - style => 'tabbed', - justify => 'right', - color => 'colored', - tab_selected => 'me', + style => 'tabbed', + justify => 'right', + color => 'colored', + tab_selected => 'me', }); - slashDisplay('user_titlebar', { - nickname => $user->{nickname}, - uid => $user->{uid}, - tab_selected => 'messages' - }); - print createMenu('messages'); # [ Message Preferences | Inbox ] slashDisplay('journuserboxes'); + my $user_titlebar = slashDisplay('user_titlebar', { + nickname => $user->{nickname}, + uid => $user->{uid}, + tab_selected => 'messages' + }, { Return => 1} ); + my $messages_menu = createMenu('messages'); # [ Message Preferences | Inbox ] slashDisplay('list_messages', { note => $note, messagecodes => $messagecodes, message_list => $message_list, + messages_menu => $messages_menu, + user_titlebar => $user_titlebar, }); footer(); } -sub list_message_rss { +sub list_messages_rss { my($messages, $constants, $user, $form) = @_; - # ... + + my @items; + my $message_list = $messages->getWebByUID(); + for my $message (@$message_list) { + my $title = "Message #$message->{id}"; + $title .= ": $message->{subject}" if $message->{subject}; + + push @items, { + story => { + 'time' => $message->{date} + }, + title => $title, + description => $message->{message} || '', + 'link' => root2abs() . "/messages.pl?op=display&id=$message->{id}", + }; + } + + xmlDisplay($form->{content_type} => { + channel => { + title => "$constants->{sitename} Messages", + description => "$constants->{sitename} Messages", + 'link' => root2abs() . '/my/inbox/', + }, + image => 1, + items => \@items, + rdfitemdesc => 1, + rdfitemdesc_html => 1, + }); } sub display_message { Index: slashjp/plugins/Messages/mysql_schema diff -u slashjp/plugins/Messages/mysql_schema:1.2 slashjp/plugins/Messages/mysql_schema:1.3 --- slashjp/plugins/Messages/mysql_schema:1.2 Fri Dec 24 05:13:39 2004 +++ slashjp/plugins/Messages/mysql_schema Wed Jul 12 20:41:50 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema,v 1.2 2004/12/23 20:13:39 oliver Exp $ +# $Id: mysql_schema,v 1.3 2006/07/12 11:41:50 sugi Exp $ # # As of July 2003 we don't have any reason I can see to ever want Index: slashjp/plugins/Messages/populate_message_log_stats.plx diff -u slashjp/plugins/Messages/populate_message_log_stats.plx:1.2 slashjp/plugins/Messages/populate_message_log_stats.plx:1.3 --- slashjp/plugins/Messages/populate_message_log_stats.plx:1.2 Fri Dec 24 05:13:39 2004 +++ slashjp/plugins/Messages/populate_message_log_stats.plx Wed Jul 12 20:41:50 2006 @@ -6,7 +6,7 @@ # you probably only want to run it once, but running it multiple times # shouldn't hurt anything # -# $Id: populate_message_log_stats.plx,v 1.2 2004/12/23 20:13:39 oliver Exp $ +# $Id: populate_message_log_stats.plx,v 1.3 2006/07/12 11:41:50 sugi Exp $ use strict; use Slash::Test shift; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:50 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:50 +0900 Subject: [Slashdotjp-dev 449] CVS update: slashjp/plugins/Login/templates Message-ID: <20060712114150.C68AE2AC102@users.sourceforge.jp> Index: slashjp/plugins/Login/templates/changePasswd;login;default diff -u slashjp/plugins/Login/templates/changePasswd;login;default:1.2 slashjp/plugins/Login/templates/changePasswd;login;default:1.3 --- slashjp/plugins/Login/templates/changePasswd;login;default:1.2 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/templates/changePasswd;login;default Wed Jul 12 20:41:50 2006 @@ -12,26 +12,30 @@ __name__ changePasswd __template__ -

[% IF form.note == "Please change your password now!"; - "Please change your password now! "; -END; note %]

- -[% title = "Change password for $user.nickname ($user.uid)" %] -[% PROCESS prefs_titlebar tab_selected='password' %] - - - - - -
+
+ [% PROCESS userboxes %] +
+[% thisnickname = user.nickname | strip_literal; + title = "Change password for $thisnickname ($user.uid)" %] +
+ [% PROCESS prefs_titlebar tab_selected='password' %] +
+[% IF form.note == "Please change your password now!"; + "Please change your password now! "; +END; note %] + [% IF constants.offer_insecure_login_link -%]

You can automatically log in by clicking - This Link and Bookmarking the resulting page. + This Link and Bookmarking the resulting page. This is totally insecure, but very convenient.

[%- END %] -
+ +
+ [% PROCESS formkey_tag %] - + [%- session = Slash.db.getDescriptions('session_login'); session_sel = Slash.createSelect('session_login', session, user.session_login, 1); @@ -50,22 +54,32 @@ other cookies for this account, requiring all other browsers using this account to reauthenticate.

- [% PROCESS formLabel value => "Current Password" comment => "To change your password, enter your current password" %] -
- - [% PROCESS formLabel value => "New Password" comment => "Enter your new password twice, must be 6-20 chars long" %] - - - -
- - - - - + +
+ To change your password, enter your current password. +
+ +
+ + +
+ Enter your new password twice, must be 6-20 chars long. +
+ + + + + + + + + + __seclev__ 500 __version__ -$Id: changePasswd;login;default,v 1.2 2004/12/31 12:36:50 oliver Exp $ +$Id: changePasswd;login;default,v 1.3 2006/07/12 11:41:50 sugi Exp $ Index: slashjp/plugins/Login/templates/data;login;default diff -u slashjp/plugins/Login/templates/data;login;default:1.2 slashjp/plugins/Login/templates/data;login;default:1.3 --- slashjp/plugins/Login/templates/data;login;default:1.2 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/templates/data;login;default Wed Jul 12 20:41:50 2006 @@ -156,4 +156,4 @@ __seclev__ 10000 __version__ -$Id: data;login;default,v 1.2 2004/12/31 12:36:50 oliver Exp $ +$Id: data;login;default,v 1.3 2006/07/12 11:41:50 sugi Exp $ Index: slashjp/plugins/Login/templates/loginForm;login;default diff -u slashjp/plugins/Login/templates/loginForm;login;default:1.2 slashjp/plugins/Login/templates/loginForm;login;default:1.3 --- slashjp/plugins/Login/templates/loginForm;login;default:1.2 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/templates/loginForm;login;default Wed Jul 12 20:41:50 2006 @@ -12,89 +12,71 @@ __name__ loginForm __template__ +
[% title = form.unickname ? 'Error Logging In' : 'Log In' %] + [% PROCESS titlebar %] +
+
+
+ Login + + [% IF form.unickname %] + [% user_uid = Slash.db.getUserUID(form.unickname) %] +

+ [% IF user.state.login_failed_reason == 'nopost' %] + This IP address or network has been used to abuse the system and logins from it have been disabled. If you feel that this is unwarranted, feel free to include your IP address ([% env.remote_addr %]) in the subject of an email to [% constants.adminmail_ban %], and we will examine why there is a ban. If you fail to include the IP address (again, in the subject!), then your message will be deleted and ignored. I mean come on, we're good, we're not psychic. + [% ELSE %] + Danger, Will Robinson! You didn't log in! You apparently put in the wrong password, or the wrong nickname. Either try again, or have your password mailed to you if you forgot your password. + [% END %] +

+ [% IF user_uid and Slash.db.getUser(user_uid, "waiting_for_account_verify") %] +

+ A request to verify your account information has been sent to the e-mail associated with this account. Your password has been reset. This is likely the reason you're having difficult logging in at the moment. +
+
+ Please check your e-mail for your updated login information or have the updated password mailed to you. +

+ [% END %] + [% IF constants.allow_anonymous %] +

+ Logging in will allow you to post comments as yourself. If you don't log in, you will only be able to post as [% Slash.getCurrentAnonymousCoward("nickname") %]. +

+ + [% ELSE %] +

+ You can only post comments if you have a valid account. +

+ [% END %] + [% END %] + + + + +
+ (6-20 characters long) +
+ + +
+
-[% PROCESS titlebar width="75%" %] - -
- - -[% IF form.unickname %] - [% user_uid = Slash.db.getUserUID(form.unickname) %] - -[% END %] - - - - - - - - - - - - - -
-

- [% IF user.state.login_failed_reason == 'nopost' %] - This IP address or network has been used to abuse the system and - logins from it have been disabled. If you feel that this is - unwarranted, feel free to include your IP address - ([% env.remote_addr %]) in the subject of an email to - [% constants.adminmail_ban %], - and we will examine why there is a ban. If you fail to include - the IP address (again, in the subject!), then your - message will be deleted and ignored. I mean come on, we're good, - we're not psychic. - [% ELSE %] - Danger, Will Robinson! You didn't log in! You apparently put - in the wrong password, or the wrong nickname. Either try again, - or have - your password mailed to you if you forgot your password. - [% END %] -

- [% IF user_uid and Slash.db.getUser(user_uid, "waiting_for_account_verify") %] -

- Note: A request to verify your account information has been sent to - the e-mail associated with this account. Your password has been reset. This - is likely the reason you're having difficult logging in at the moment. -

-

- Please check your e-mail for your updated login information or - have - the updated password mailed to you. -

- [% END %] - - [% IF constants.allow_anonymous %]

- Logging in will allow you to post comments as yourself. If you - don't log in, you will only be able to post as - [% Slash.getCurrentAnonymousCoward("nickname") %]. + Forget your password? Have your password mailed to you by entering your nickname, uid, or email address.

- - [% ELSE %]

- You can only post comments if you have a valid account. + Create a new account if you don't have one already.

- - [% END %] -
Nickname: -
Password: (6-20 characters long) -
Public Terminal
-
- -

-Forget your password? Have your -password mailed to you by entering your nickname, uid, or email address.
-Create a new account -if you don't have one already.
-

- +
+
__seclev__ 500 __version__ -$Id: loginForm;login;default,v 1.2 2004/12/31 12:36:50 oliver Exp $ +$Id: loginForm;login;default,v 1.3 2006/07/12 11:41:50 sugi Exp $ Index: slashjp/plugins/Login/templates/newUserForm;login;default diff -u slashjp/plugins/Login/templates/newUserForm;login;default:1.1 slashjp/plugins/Login/templates/newUserForm;login;default:1.2 --- slashjp/plugins/Login/templates/newUserForm;login;default:1.1 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/templates/newUserForm;login;default Wed Jul 12 20:41:50 2006 @@ -13,48 +13,50 @@ __name__ newUserForm __template__ -[% IF note %][% note %][% END %] - -[% PROCESS titlebar title="Create Account" width="100%" %] - -[% chars = constants.nick_chars; - chars = chars.replace('abcdefghijklmnopqrstuvwxyz', 'a-z'); - chars = chars.replace('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A-Z'); - chars = chars.replace('0123456789', '0-9'); -%] - -
- -[% PROCESS formkey_tag %] - - - - - - - - - - - - -

(Note: only the characters [% chars | strip_literal %], plus space, - are allowed in nicknames, and all others will be stripped out.)
-

- Nick Name
- -
-

Email address to send your registration information to. - This address will not be displayed on [% constants.sitename %] - without you setting your preferences to display it.

-
- Real Email
- -
- Retype Real Email (these two email addresses must match)
-
- Replies to my comments will be mailed to me
- Send me the newsletter
- Send me the daily headlines
- My timezone is [% +
+ [% PROCESS titlebar title="Create Account" %] +
+ [% IF note %] + [% note %] + [% END %] + [% chars = constants.nick_chars; + chars = chars.replace('abcdefghijklmnopqrstuvwxyz', 'a-z'); + chars = chars.replace('ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'A-Z'); + chars = chars.replace('0123456789', '0-9'); + %] + +
+ + [% PROCESS formkey_tag %] + + +
+ (Note: only the characters [% chars | strip_literal %], plus space, are allowed in nicknames, and all others will be stripped out.) +
+ + + + +
+ Enter a valid email address twice to send your registration information to. This address will not be displayed on [% constants.sitename %] without you setting your preferences to display it. +
+ + + + + [% USE this_format = format('%+0.4d %s'); this_tzdescs = Slash.db.getDescriptions('tzdescription'); this_tzcodes = Slash.db.getDescriptions('tzcodes'); @@ -69,36 +71,33 @@ Slash.createSelect('tzcode', these_tzdescs, this_tzcode, 1, 0, this_tzcodes.nsort ); - %]
+ %] +
+ Select your current local time. +
[% IF constants.plugin.HumanConf && constants.hc && constants.hc_sw_newuser && user.state.hc %] [% IF user.state.hcinvalid %] [% user.state.hcerror %] [% ELSE %] - - - - -
[% user.state.hcquestion %][% user.state.hchtml %]
+

Click the button to create your account and be mailed a password.

- + [% END %] [% ELSE %] - + [% END %] - -
+
- -

-Log in to [% constants.sitename %].
-Forget your password? Have your -password mailed to you by entering your nickname, uid, or email address. -

+

+ Log in to [% constants.sitename %].
Forget your password? Have your password mailed to you by entering your nickname, uid, or email address. +

+ + __seclev__ 10000 __version__ -$Id: newUserForm;login;default,v 1.1 2004/12/31 12:36:50 oliver Exp $ +$Id: newUserForm;login;default,v 1.2 2006/07/12 11:41:50 sugi Exp $ Index: slashjp/plugins/Login/templates/sendPasswdForm;login;default diff -u slashjp/plugins/Login/templates/sendPasswdForm;login;default:1.2 slashjp/plugins/Login/templates/sendPasswdForm;login;default:1.3 --- slashjp/plugins/Login/templates/sendPasswdForm;login;default:1.2 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Login/templates/sendPasswdForm;login;default Wed Jul 12 20:41:50 2006 @@ -13,27 +13,19 @@ __template__ [% IF note %][% note %][% END %] -
- +[% PROCESS titlebar title="Mail Password" %] +
+ +
+ + [% PROCESS formkey_tag %] - - - - - - - - - - - -
-[% PROCESS titlebar title="Mail Password" width="100%" %] -

Forget your password? Enter your nickname, UID, or email address here to have the system mail your password to you.

-
Nickname/UID/Email - + Nickname/UID/Email +
[% IF constants.plugin.HumanConf && constants.hc && constants.hc_sw_mailpasswd && user.state.hc %] [% IF user.state.hcinvalid %] @@ -42,19 +34,16 @@ -
[% user.state.hcquestion %] [% user.state.hchtml %]
- + [% END %] [% ELSE %] - + [% END %] - -
+
[% IF user.is_anon %]

@@ -63,9 +52,9 @@ if you don't have one already.

[% END %] - +
__seclev__ 500 __version__ -$Id: sendPasswdForm;login;default,v 1.2 2004/12/31 12:36:50 oliver Exp $ +$Id: sendPasswdForm;login;default,v 1.3 2006/07/12 11:41:50 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:51 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:51 +0900 Subject: [Slashdotjp-dev 450] CVS update: slashjp/plugins/Messages/DB/MySQL Message-ID: <20060712114151.2B0D22AC0F1@users.sourceforge.jp> Index: slashjp/plugins/Messages/DB/MySQL/MySQL.pm diff -u slashjp/plugins/Messages/DB/MySQL/MySQL.pm:1.3 slashjp/plugins/Messages/DB/MySQL/MySQL.pm:1.4 --- slashjp/plugins/Messages/DB/MySQL/MySQL.pm:1.3 Fri Dec 31 21:36:50 2004 +++ slashjp/plugins/Messages/DB/MySQL/MySQL.pm Wed Jul 12 20:41:51 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: MySQL.pm,v 1.3 2004/12/31 12:36:50 oliver Exp $ +# $Id: MySQL.pm,v 1.4 2006/07/12 11:41:51 sugi Exp $ package Slash::Messages::DB::MySQL; @@ -31,7 +31,7 @@ # needs to be second! figure it out. -- pudge use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; my %descriptions = ( 'deliverymodes' @@ -137,11 +137,12 @@ } sub log { - my($self, $msg, $mode) = @_; + my($self, $msg, $mode, $count) = @_; + $count = 1 if !$count || $count < 1; my $table = $self->{_log_table}; $msg->{user} ||= {}; - $self->sqlInsert($table, { + my %data = ( id => $msg->{id}, user => (ref($msg->{user}) ? ($msg->{user}{uid} || 0) @@ -153,7 +154,10 @@ ), code => $msg->{code}, mode => $mode, - }, { delayed => 1 }); + ); + + $self->sqlInsert($table, \%data, { delayed => 1 }) + for 1 .. $count; } sub _create_web { @@ -222,7 +226,7 @@ my $prime = "message_web.id=message_web_text.id AND user"; my $other = "ORDER BY date ASC"; - my $id_db = $self->sqlQuote($uid || $ENV{SLASH_USER}); + my $id_db = $self->sqlQuote($uid || getCurrentUser('uid')); my $data = $self->sqlSelectAllHashrefArray( $cols, $table, "$prime=$id_db", $other ); @@ -234,7 +238,7 @@ my $table = $self->{_web_table}; my $cols = "readed"; - my $uid_db = $self->sqlQuote($uid || $ENV{SLASH_USER}); + my $uid_db = $self->sqlQuote($uid || getCurrentUser('uid')); my $data = $self->sqlSelectAll( $cols, $table, "user=$uid_db AND " . "$self->{_web_table1}.$self->{_web_prime1} = $self->{_web_table2}.$self->{_web_prime2}", @@ -267,7 +271,7 @@ my $table = $self->{_drop_table}; my $cols = $self->{_drop_cols}; - $count = 1 if $count =~ /\D/; + $count = 1 if $count && $count =~ /\D/; my $other = "ORDER BY date ASC"; $other .= " LIMIT $count" if $count; @@ -370,12 +374,12 @@ my $where2 = "$prime1=$id_db"; unless ($override) { - $uid ||= $ENV{SLASH_USER}; + $uid ||= getCurrentUser('uid'); return 0 unless $uid; my $uid_db = $self->sqlQuote($uid); my $where = $where1 . " AND user=$uid_db"; my($check) = $self->sqlSelect('user', $table1, $where); - return 0 unless $check eq $uid; + return 0 unless defined($check) && $check eq $uid; } $self->sqlDo("DELETE FROM $table1 WHERE $where1"); @@ -466,7 +470,7 @@ if ($acl) { my $acl_q = $self->sqlQuote($acl); my $aclt = "$table,users_acl"; - my $aclw = " users_acl.uid = users_messages.uid AND users_acl.acl=$acl_q"; + my $aclw = "$where AND users_acl.uid = users_messages.uid AND users_acl.acl=$acl_q"; my $aclu = $self->sqlSelectColArrayref($cols, $aclt, $aclw) || []; push @users, @$aclu; } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:51 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:51 +0900 Subject: [Slashdotjp-dev 451] CVS update: slashjp/plugins/NewsVac Message-ID: <20060712114151.C3D7B2AC104@users.sourceforge.jp> Index: slashjp/plugins/NewsVac/NewsVac.pm diff -u slashjp/plugins/NewsVac/NewsVac.pm:1.2 slashjp/plugins/NewsVac/NewsVac.pm:1.3 --- slashjp/plugins/NewsVac/NewsVac.pm:1.2 Fri Dec 24 05:13:40 2004 +++ slashjp/plugins/NewsVac/NewsVac.pm Wed Jul 12 20:41:51 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: NewsVac.pm,v 1.2 2004/12/23 20:13:40 oliver Exp $ +# $Id: NewsVac.pm,v 1.3 2006/07/12 11:41:51 sugi Exp $ package Slash::NewsVac; @@ -79,7 +79,7 @@ use Slash::Display; use Slash::Utility; -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; use vars qw($VERSION $callback_ref); @@ -6281,4 +6281,4 @@ =head1 VERSION -$Id: NewsVac.pm,v 1.2 2004/12/23 20:13:40 oliver Exp $ +$Id: NewsVac.pm,v 1.3 2006/07/12 11:41:51 sugi Exp $ Index: slashjp/plugins/NewsVac/PLUGIN diff -u slashjp/plugins/NewsVac/PLUGIN:1.3 slashjp/plugins/NewsVac/PLUGIN:1.4 --- slashjp/plugins/NewsVac/PLUGIN:1.3 Fri Dec 31 21:36:51 2004 +++ slashjp/plugins/NewsVac/PLUGIN Wed Jul 12 20:41:51 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.3 2004/12/31 12:36:51 oliver Exp $ +# $Id: PLUGIN,v 1.4 2006/07/12 11:41:51 sugi Exp $ name=NewsVac description="NewsForge NewsVac" mysql_schema=mysql_schema Index: slashjp/plugins/NewsVac/dump diff -u slashjp/plugins/NewsVac/dump:1.3 slashjp/plugins/NewsVac/dump:1.4 --- slashjp/plugins/NewsVac/dump:1.3 Fri Dec 31 21:36:51 2004 +++ slashjp/plugins/NewsVac/dump Wed Jul 12 20:41:51 2006 @@ -1,5 +1,5 @@ # -# $Id: dump,v 1.3 2004/12/31 12:36:51 oliver Exp $ +# $Id: dump,v 1.4 2006/07/12 11:41:51 sugi Exp $ # # put this shit into sql dump (for select) @@ -23,13 +23,13 @@ # INSERT INTO miner (miner_id, name, last_edit, last_edit_aid, owner_aid, progress, pre_stories_text, post_stories_text, pre_stories_regex, post_stories_regex, extract_vars, extract_regex, tweak_code, comment) VALUES (2,'none',20000629201648,'God','God','broken','','','','','','ThisTextIsNotExpectedToMatchAnything','','This is a placeholder, do not edit this. -Slashteam'); -INSERT INTO miner (miner_id, name, last_edit, last_edit_aid, owner_aid, progress, pre_stories_text, post_stories_text, pre_stories_regex, post_stories_regex, extract_vars, extract_regex, tweak_code, comment) VALUES (1,'osdn',20020409034422,'God','God','ok','','','(?i)^(.+)','(?i)(.+)$','url title','(?i)
  • \r\n(.+?)\r\n
  • ','$source = \"OSDN\";','This is the default miner for NewsVac which checks OSDN\'s website.'); +INSERT INTO miner (miner_id, name, last_edit, last_edit_aid, owner_aid, progress, pre_stories_text, post_stories_text, pre_stories_regex, post_stories_regex, extract_vars, extract_regex, tweak_code, comment) VALUES (1,'ostg',20020409034422,'God','God','ok','','','(?i)^(.+)','(?i)(.+)$','url title','(?i)
  • \r\n(.+?)\r\n
  • ','$source = \"OSTG\";','This is the default miner for NewsVac which checks OSTG\'s website.'); # # Dumping data for table 'url_info' # -INSERT INTO url_info (url_id, url_digest, url, url_base, is_success, last_attempt, last_success, believed_fresh_until, status_code, reason_phrase, content_type, title, miner_id) VALUES (1,'96d6daa5cae137dd288f74caa7fc0fca','http://www.osdn.com/',NULL,1,'2002-04-09 07:39:41','2002-04-09 07:39:41','2002-04-09 08:39:41',200,'OK','text/html; charset=ISO-8859-1','OSDN: Open Source Development Network',1); +INSERT INTO url_info (url_id, url_digest, url, url_base, is_success, last_attempt, last_success, believed_fresh_until, status_code, reason_phrase, content_type, title, miner_id) VALUES (1,'96d6daa5cae137dd288f74caa7fc0fca','http://www.ostg.com/',NULL,1,'2002-04-09 07:39:41','2002-04-09 07:39:41','2002-04-09 08:39:41',200,'OK','text/html; charset=ISO-8859-1','OSTG: Open Source Development Network',1); INSERT INTO menus (menu, label, value, seclev, menuorder) VALUES ('admin', 'NewsVac', '[% gSkin.rootdir %]/newsvac.pl', 5000, 100); INSERT INTO menus (menu, label, value, seclev, menuorder) VALUES ('newsvac','Miners','[% gSkin.rootdir %]/newsvac.pl?op=listminers',10000,1); @@ -39,7 +39,7 @@ # This functionality was planned but never finished. Maybe someday? #INSERT INTO menus (menu, label, value, seclev, menuorder) VALUES ('newsvac','Nuggets','[% gSkin.rootdir %]/newsvac.pl?op=listnuggets',10000,10); -INSERT into sections (section, artcount, title) VALUES ('newsvac', 0, 'NewsVac Links'); +#INSERT into sections (section, artcount, title) VALUES ('newsvac', 0, 'NewsVac Links'); INSERT INTO vars (name, value, description) VALUES ('newsvac_topic', 1, 'Default topic for NewsVac items that have been robo-submitted'); INSERT INTO vars (name, value, description) VALUES ('newsvac_section', 'newsvac', 'Default section for NewsVac items that have been robo-submitted'); Index: slashjp/plugins/NewsVac/mysql_schema diff -u slashjp/plugins/NewsVac/mysql_schema:1.2 slashjp/plugins/NewsVac/mysql_schema:1.3 --- slashjp/plugins/NewsVac/mysql_schema:1.2 Fri Dec 24 05:13:40 2004 +++ slashjp/plugins/NewsVac/mysql_schema Wed Jul 12 20:41:51 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema,v 1.2 2004/12/23 20:13:40 oliver Exp $ +# $Id: mysql_schema,v 1.3 2006/07/12 11:41:51 sugi Exp $ # DROP TABLE IF EXISTS newsvac_keywords; @@ -38,7 +38,7 @@ DROP TABLE IF EXISTS url_info; CREATE TABLE url_info ( - url_id INT(10) UNSIGNED DEFAULT '0' NOT NULL auto_increment, + url_id INT(10) UNSIGNED NOT NULL auto_increment, url_digest VARCHAR(32) NOT NULL, url TEXT NOT NULL, url_base TEXT, @@ -72,7 +72,7 @@ DROP TABLE IF EXISTS rel; CREATE TABLE rel ( - rel_id INT(10) UNSIGNED DEFAULT '0' NOT NULL auto_increment, + rel_id INT(10) UNSIGNED NOT NULL auto_increment, from_url_id INT(10) UNSIGNED DEFAULT '0' NOT NULL, to_url_id INT(10) UNSIGNED DEFAULT '0' NOT NULL, parse_code enum('html_linkextor','miner','nugget','plaintext') DEFAULT 'html_linkextor' NOT NULL, @@ -93,7 +93,7 @@ DROP TABLE IF EXISTS miner; CREATE TABLE miner ( - miner_id INT(10) UNSIGNED DEFAULT '0' NOT NULL auto_increment, + miner_id INT(10) UNSIGNED NOT NULL auto_increment, name VARCHAR(20) DEFAULT '' NOT NULL, last_edit timestamp(14), last_edit_aid VARCHAR(30), @@ -117,7 +117,7 @@ DROP TABLE IF EXISTS spider; CREATE TABLE spider ( - spider_id INT(10) UNSIGNED DEFAULT '0' NOT NULL auto_increment, + spider_id INT(10) UNSIGNED NOT NULL auto_increment, name VARCHAR(20) DEFAULT '' NOT NULL, last_edit timestamp(14), last_edit_aid VARCHAR(30), @@ -137,7 +137,7 @@ # Yes, I said "BIGINT" DROP TABLE IF EXISTS spider_timespec; CREATE TABLE spider_timespec ( - timespec_id INT(10) UNSIGNED DEFAULT '0' NOT NULL auto_increment, + timespec_id INT(10) UNSIGNED NOT NULL auto_increment, name VARCHAR(20) NOT NULL, timespec VARCHAR(64) DEFAULT '' NOT NULL, results VARCHAR(30) DEFAULT '' NOT NULL, Index: slashjp/plugins/NewsVac/newsvac.pl diff -u slashjp/plugins/NewsVac/newsvac.pl:1.3 slashjp/plugins/NewsVac/newsvac.pl:1.4 --- slashjp/plugins/NewsVac/newsvac.pl:1.3 Fri Dec 31 21:36:51 2004 +++ slashjp/plugins/NewsVac/newsvac.pl Wed Jul 12 20:41:51 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: newsvac.pl,v 1.3 2004/12/31 12:36:51 oliver Exp $ +# $Id: newsvac.pl,v 1.4 2006/07/12 11:41:51 sugi Exp $ use strict; use Slash 2.003; # require Slash 2.3.x @@ -15,7 +15,7 @@ use vars qw($VERSION); -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; ################################################################## sub main { Index: slashjp/plugins/NewsVac/newsvac.pod diff -u slashjp/plugins/NewsVac/newsvac.pod:1.1.1.1 slashjp/plugins/NewsVac/newsvac.pod:1.2 --- slashjp/plugins/NewsVac/newsvac.pod:1.1.1.1 Wed Jan 28 06:55:04 2004 +++ slashjp/plugins/NewsVac/newsvac.pod Wed Jul 12 20:41:51 2006 @@ -149,7 +149,7 @@ =head2 Nuggets -Nuggets are special URLs that contain the URL, title, slug, and source of a mined URL. The source is where the data came from (such as "OSDN"); the slug is some additional text apart from the title (like introtext). +Nuggets are special URLs that contain the URL, title, slug, and source of a mined URL. The source is where the data came from (such as "OSTG"); the slug is some additional text apart from the title (like introtext). =head2 Parsers @@ -303,8 +303,11 @@ =head1 CHANGES $Log: newsvac.pod,v $ - Revision 1.1.1.1 2004/01/27 21:55:04 oliver - Initial Import of Slashcode R_2_3_0_113 + Revision 1.2 2006/07/12 11:41:51 sugi + ovewrite by upstream head + + Revision 1.8 2005/03/11 19:58:11 pudge + Update 2005, OSTG, etc. Revision 1.7 2002/10/21 15:11:35 pudge Digest in base64 not handled properly (was 16 chars, needed to be 22); screw it, go to hex, and increase column to 32. @@ -338,9 +341,9 @@ =head1 AUTHOR -This document is being maintained by Chris Nandor Epudge ¡÷ osdn.comE, with aid from Jamie McCarthy, Cliff Wood, Brian Aker, and Robin Miller. +This document is being maintained by Chris Nandor Epudge ¡÷ ostg.comE, with aid from Jamie McCarthy, Cliff Wood, Brian Aker, and Robin Miller. =head1 VERSION -$Id: newsvac.pod,v 1.1.1.1 2004/01/27 21:55:04 oliver Exp $ +$Id: newsvac.pod,v 1.2 2006/07/12 11:41:51 sugi Exp $ Index: slashjp/plugins/NewsVac/prep diff -u slashjp/plugins/NewsVac/prep:1.2 slashjp/plugins/NewsVac/prep:1.3 --- slashjp/plugins/NewsVac/prep:1.2 Fri Dec 24 05:13:40 2004 +++ slashjp/plugins/NewsVac/prep Wed Jul 12 20:41:51 2006 @@ -1,5 +1,5 @@ # -# $Id: prep,v 1.2 2004/12/23 20:13:40 oliver Exp $ +# $Id: prep,v 1.3 2006/07/12 11:41:51 sugi Exp $ # UPDATE spider_timespec SET last_run=now() WHERE last_run=0; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:51 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:51 +0900 Subject: [Slashdotjp-dev 452] CVS update: slashjp/plugins/NewsVac/tasks Message-ID: <20060712114151.E97122AC0EB@users.sourceforge.jp> Index: slashjp/plugins/NewsVac/tasks/newsvac_gc.pl diff -u slashjp/plugins/NewsVac/tasks/newsvac_gc.pl:1.1.1.1 slashjp/plugins/NewsVac/tasks/newsvac_gc.pl:1.2 --- slashjp/plugins/NewsVac/tasks/newsvac_gc.pl:1.1.1.1 Wed Jan 28 06:55:04 2004 +++ slashjp/plugins/NewsVac/tasks/newsvac_gc.pl Wed Jul 12 20:41:51 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # -# $Id: newsvac_gc.pl,v 1.1.1.1 2004/01/27 21:55:04 oliver Exp $ +# $Id: newsvac_gc.pl,v 1.2 2006/07/12 11:41:51 sugi Exp $ # -# SlashD Task (c) OSDN 2001 +# SlashD Task (c) OSTG 2001 # # Description: Performs garbage collection on NewsVac data. # Index: slashjp/plugins/NewsVac/tasks/run_spider.pl diff -u slashjp/plugins/NewsVac/tasks/run_spider.pl:1.1.1.1 slashjp/plugins/NewsVac/tasks/run_spider.pl:1.2 --- slashjp/plugins/NewsVac/tasks/run_spider.pl:1.1.1.1 Wed Jan 28 06:55:04 2004 +++ slashjp/plugins/NewsVac/tasks/run_spider.pl Wed Jul 12 20:41:51 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # -# $Id: run_spider.pl,v 1.1.1.1 2004/01/27 21:55:04 oliver Exp $ +# $Id: run_spider.pl,v 1.2 2006/07/12 11:41:51 sugi Exp $ # -# SlashD Task (c) OSDN 2001 +# SlashD Task (c) OSTG 2001 # # Description: Performs Spidering runs within Task architechture. # Converted from original cron jobs from NewsForge From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:52 +0900 Subject: [Slashdotjp-dev 453] CVS update: slashjp/plugins/OAI Message-ID: <20060712114152.A8D0F2AC0EB@users.sourceforge.jp> Index: slashjp/plugins/OAI/MANIFEST diff -u /dev/null slashjp/plugins/OAI/MANIFEST:1.1 --- /dev/null Wed Jul 12 20:41:52 2006 +++ slashjp/plugins/OAI/MANIFEST Wed Jul 12 20:41:52 2006 @@ -0,0 +1,4 @@ +Makefile.PL +MANIFEST +OAI.pm +oai.pl Index: slashjp/plugins/OAI/Makefile.PL diff -u /dev/null slashjp/plugins/OAI/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:52 2006 +++ slashjp/plugins/OAI/Makefile.PL Wed Jul 12 20:41:52 2006 @@ -0,0 +1,8 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Slash::XML::OAI', + 'VERSION_FROM' => 'OAI.pm', # finds $VERSION + 'PM' => { 'OAI.pm' => '$(INST_LIBDIR)/OAI.pm' }, +); Index: slashjp/plugins/OAI/OAI.pm diff -u /dev/null slashjp/plugins/OAI/OAI.pm:1.1 --- /dev/null Wed Jul 12 20:41:52 2006 +++ slashjp/plugins/OAI/OAI.pm Wed Jul 12 20:41:52 2006 @@ -0,0 +1,675 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: OAI.pm,v 1.1 2006/07/12 11:41:52 sugi Exp $ + +package Slash::XML::OAI; + +=head1 NAME + +Slash::XML::OAI - Perl extension for OAI2 Repository Responses + + +=head1 SYNOPSIS + + use Slash::XML; + xmlDisplay(%data); + + +=head1 DESCRIPTION + +LONG DESCRIPTION. + + +=head1 EXPORTED FUNCTIONS + +=cut + +use strict; +use Slash; +use Slash::Utility; +use XML::RSS; +use base 'Slash::XML'; +use vars qw($VERSION); + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +our %Verbs = ( + GetRecord => \&GetRecord, + Identify => \&Identify, + ListIdentifiers => \&ListIdentifiers, + ListMetadataFormats => \&ListMetadataFormats, + ListRecords => \&ListRecords, + ListSets => \&ListSets, +); + +our %Formats = ( + oai_dc => { + schema => 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd', + namespace => 'http://www.openarchives.org/OAI/2.0/oai_dc/', + } +); + +our %Sets = ( + article => { + name => 'Article', + }, +); + + +#======================================================================== + +=head2 create(PARAM) + +Creates OAI repository responses. + +=over 4 + +=item Parameters + +=over 4 + +=item PARAM + +Hashref of parameters. Currently supported options are below. + +=over 4 + +=item verb + +Required. Must be one of C, C, C, +C, C, C. + +=back + +=back + +=item Return value + +The complete XML data as a string. + +=back + +=cut + +sub create { + my($class, $params) = @_; + my $self = bless {}, $class; + + my $constants = getCurrentStatic(); + my $gSkin = getCurrentSkin(); + + my $options = { + verb => $params->{verb}, + url => $params->{url} || "$constants->{absolutedir}/oai.pl", + args => $params->{args} || {} + }; + + my $xml; + my $verb = $Verbs{$params->{verb}}; + if (! $verb) { + $options->{error} = 'badVerb'; + } else { + $xml = $self->$verb($options); + } + + my $header = $self->head($options); + my $footer = $self->foot($options); + + return $header . $xml . $footer; +} + + +sub GetRecord { + my($self, $options) = @_; + my $xml; + + # copy args + my %args = map { $_ => $options->{args}{$_} } keys %{$options->{args}}; + my $identifier = delete $args{identifier}; + my $metadataPrefix = delete $args{metadataPrefix}; + + if (keys %args || !$identifier || !$metadataPrefix) { + push @{$options->{error}}, 'badArgument'; + } + if ($metadataPrefix && !$Formats{$metadataPrefix}) { + push @{$options->{error}}, 'cannotDisseminateFormat'; + } + + my $record = $self->_get_identifier($identifier); + if (!$record->{metadata}) { + push @{$options->{error}}, 'idDoesNotExist'; + } + return if $options->{error}; + + $xml = $self->_print_record([$record]); + + return $xml; +} + + +sub ListIdsOrRecords { + my($self, $options) = @_; + my $xml; + my %dates; + + # copy args + my %args = map { $_ => $options->{args}{$_} } keys %{$options->{args}}; + my $resumptionToken = delete $args{resumptionToken}; + + if ($resumptionToken) { + # resumptionToken is exclusive + if (scalar(keys %{$options->{args}}) > 1) { + push @{$options->{error}}, 'badArgument'; + } + + my $rt_args = $self->_parse_resumptionToken($resumptionToken); + if (keys %$rt_args) { + my $optargs = $options->{args}; + $optargs->{metadataPrefix} = delete $rt_args->{metadataPrefix}; + $optargs->{set} = delete $rt_args->{set}; + $optargs->{from} = delete $rt_args->{from}; + $optargs->{'until'} = delete $rt_args->{'until'}; + $options->{nextStart} = delete $rt_args->{nextStart}; + %args = map { $_ => $options->{args}{$_} } keys %{$options->{args}}; + delete $args{resumptionToken}; + } else { + push @{$options->{error}}, 'badResumptionToken'; + } + + return if $options->{error}; + } + + my $metadataPrefix = delete $args{metadataPrefix}; + my $set = delete $args{set}; + $dates{from} = delete $args{from}; + $dates{'until'} = delete $args{'until'}; + + # metadataPrefix required + if (keys %args || !$metadataPrefix) { + push @{$options->{error}}, 'badArgument'; + } + if ($metadataPrefix && !$Formats{$metadataPrefix}) { + push @{$options->{error}}, 'cannotDisseminateFormat'; + } + if ($set && !keys %Sets) { + push @{$options->{error}}, 'noSetHierarchy'; + } + return if $options->{error}; + + if (defined $options->{nextStart} && $options->{nextStart} =~ /\D/) { + $options->{error} = { + badArgument => "nextStart must be an integer" + }; + return; + } + + for my $date (qw(from until)) { + next unless $dates{$date}; + if ($dates{$date} =~ /^(\d{4})-(\d{2})-(\d{2})(T(\d{2}):(\d{2}):(\d{2})Z)?$/) { + if (!$4) { + $dates{$date} .= $date eq 'from' + ? 'T00:00:00Z' + : 'T23:59:59Z'; + } + } else { + $options->{error} = { + badArgument => "Incorrectly formed '$date' date: $dates{$date}" + }; + return; + } + } + + if ($dates{from} && $dates{'until'} && $dates{from} gt $dates{'until'}) { + $options->{error} = { + badArgument => "'from' date $dates{from} is greater than 'until' date $dates{until}" + }; + return; + } + + + my($records, $next) = $self->_find_records($options, \%dates, $set); + if (!@$records) { + push @{$options->{error}}, 'noRecordsMatch'; + return; + } else { + $xml .= $self->_print_record($records, $options); + } + + $xml .= $self->_print_resumptionToken($options, $next) if $next; + + # clean up ... we know if we are here, this is correct + $options->{args} = { resumptionToken => $resumptionToken } if $resumptionToken; + + return $xml; +} + + +sub ListIdentifiers { + my($self, $options) = @_; + $options->{identifiers} = 1; + return $self->ListIdsOrRecords($options); +} + + +sub ListRecords { + my($self, $options) = @_; + $options->{records} = 1; + return $self->ListIdsOrRecords($options); +} + + +sub ListMetadataFormats { + my($self, $options) = @_; + my $xml; + + # identifier is only allowed argument, and we ignore it at this time, + # as we do the same format for everything + # if we do support identifier, also support + # idDoesNotExist and noMetadataFormats errors + if (grep {$_ ne 'identifier' } keys %{$options->{args}}) { + push @{$options->{error}}, 'badArgument'; + return; + } + + for my $prefix (keys %Formats) { + my $schema = $self->encode($Formats{$prefix}{schema}, 'link'); + my $namespace = $self->encode($Formats{$prefix}{namespace}, 'link'); + $xml .= < + $prefix + $schema + $namespace + +EOT + } + + return $xml; +} + + +{ +# compression currently unsupported +my @elements = qw( + repositoryName + baseURL + protocolVersion + adminEmail + earliestDatestamp + deletedRecord + granularity +); +# compression + +my @descriptions; +push @descriptions, <<'EOT'; + + oai + DLIST.OAI2 + : + oai:DLIST.OAI2:23 + +EOT + +sub Identify { + my($self, $options) = @_; + my $xml; + my $constants = getCurrentStatic(); + + if (keys %{$options->{args}}) { + $options->{error} = 'badArgument'; + return; + } + + for my $el (@elements) { + my $value; + if ($el eq 'repositoryName') { + $value = "$constants->{sitename} OAI Repository", + } elsif ($el eq 'baseURL') { + $value = $options->{url}, + } elsif ($el eq 'protocolVersion') { + $value = '2.0'; + } elsif ($el eq 'adminEmail') { + # we could use a new var for this, and have multiple values + $value = $constants->{adminmail}; + } elsif ($el eq 'earliestDatestamp') { + # XXX this could be better somehow ... probably a var + $value = Slash::XML->date2iso8601(0, 1); + } elsif ($el eq 'deletedRecord') { + # no, persistent, transient + $value = 'no'; + } elsif ($el eq 'granularity') { + $value = 'YYYY-MM-DDThh:mm:ssZ'; + } + + $xml .= sprintf(" <%s>%s\n", + $el, $self->encode($value, 'link'), $el, + ); + } + + if (@descriptions) { + $xml .= " \n$_ \n" + for @descriptions; + } + + return $xml; +} +} + + +sub ListSets { + my($self, $options) = @_; + my $xml; + + if (!keys %Sets) { + push @{$options->{error}}, 'noSetHierarchy'; + } + # resumptionToken is the only allowed argument, and we ignore it at this time + if (grep {$_ ne 'resumptionToken' } keys %{$options->{args}}) { + push @{$options->{error}}, 'badArgument'; + } + if ($options->{args}{resumptionToken}) { + push @{$options->{error}}, 'badResumptionToken'; + } + return if $options->{error}; + + for my $set (keys %Sets) { + $xml .= sprintf(<encode($_, 'link') } $set, $Sets{$set}{name}); + + %s + %s + +EOT + } + + return $xml; +} + + +sub head { + my($self, $options) = @_; + my $date = $self->date2iso8601($options->{date}, 1); + my $url = $self->encode($options->{url}, 'link'); + + my $args = ''; + # no args if error + if (!$options->{error}) { + $args = qq[ verb="$options->{verb}"]; + for my $key (keys %{$options->{args}}) { + my $val = strip_attribute($options->{args}{$key}, 'link'); + $args .= qq[ $key="$val"]; + } + } + + # third param is results, unless error, in which case it is the error + my $third; + if ($options->{error}) { + my $errs = $options->{error}; + if (!ref $errs) { + $errs = [ $errs ]; + } + + if (ref $errs eq 'ARRAY') { + for my $err (@$errs) { + $third .= qq[ \n]; + } + } elsif (ref $errs eq 'HASH') { + for my $err (keys %$errs) { + my $str = $self->encode($errs->{$err}); + if ($str) { + $third .= sprintf( + qq[ %s\n], + $errs->{$err} + ); + } else { + $third .= qq[ \n]; + } + } + } + chomp $third; + } else { + $third = " <$options->{verb}>"; + } + + return < + + $date + $url +$third +EOT +} + +sub foot { + my($self, $options) = @_; + my $close = $options->{error} ? '' : " {verb}>\n"; + return < +EOT +} + + + +# oai:slashdot.org:article/$id +sub _get_identifier { + my($self, $identifier) = @_; + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $constants = getCurrentStatic(); + + my $site = $constants->{basedomain}; + my $data = { identifier => $identifier }; + + $identifier =~ m|^oai:\Q$site\E:(\w+)/(\w+)$|; + $data->{type} = $1; + $data->{id} = $2; + + if ($data->{type} eq 'article') { + my $record = $reader->getStory($data->{id}); + if ($record) { + ($data->{datestamp} = $record->{'last_update'}) =~ + s{^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})} + {$1-$2-$3T$4:$5:$6Z}x; + + my $md = {}; + $md->{title} = $record->{title}; + $md->{creator} = $reader->getUser($record->{uid}, 'nickname'); + $md->{date} = $record->{'time'}; + $md->{identifier} = "$constants->{absolutedir}/article.pl?sid=$record->{sid}"; + + $md->{description} = < +$record->{introtext} + +EOT + $md->{description} .= <{bodytext}; + +
    +$record->{bodytext} +
    +EOT + $md->{description} = parseSlashizedLinks(processSlashTags($md->{description})); + + + my $topics = $reader->getStoryTopicsRendered($record->{stoid}); + my $tree = $reader->getTopicTree; + $md->{subject} = [ + map { $tree->{$_}{keyword} } + @$topics + ]; + + $data->{metadata} = $md; + } + } + + return $data; +} + + +sub _create_identifier { + my($self, $data) = @_; + my $site = getCurrentStatic('basedomain'); + my $identifier = 'oai:'; + + $identifier .= $site; + $identifier .= ":$data->{type}/$data->{id}"; + + return $identifier; +} + + +sub _print_record { + my($self, $records, $options) = @_; + my $xml; + + my $source = [ getCurrentStatic('basedomain') ]; + + for my $record (@$records) { + # XXX setSpec hardcoded for now + my $identifier = $self->encode($record->{identifier}, 'link'); + my $datestamp = $self->date2iso8601($record->{datestamp}, 1); + $xml .= <<'EOT' unless $options->{verb} eq 'ListIdentifiers'; + +EOT + + $xml .= sprintf(< + %s + %s + article + +EOT + next if $options->{verb} eq 'ListIdentifiers'; + $xml .= <<'EOT'; + + +EOT + + # same on all: publisher, rights, type, format, language + # dunno: source, relation, coverage + for my $dc (qw(source title creator subject description contributor date identifier)) { + my $values; + if ($dc eq 'source') { + $values = $source; + } else { + next unless defined $record->{metadata}{$dc} + && length $record->{metadata}{$dc}; + $values = $record->{metadata}{$dc}; + } + unless (ref $values eq 'ARRAY') { + $values = [ $values ]; + } + + for (@$values) { + my $value = $dc eq 'date' + ? $self->date2iso8601($_, 1) + : $self->encode($_, 'link'); + $xml .= sprintf(<%s +EOT + } + } + $xml .= < + + +EOT + } + + return $xml; +} + + +sub _find_records { + my($self, $options, $dates, $set) = @_; + + my $limit = 100; # XXX var, oai_list_limit? + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $type = $options->{type} || 'article'; + my($records, @return); + + my $timecol = 'last_update'; + + my $start = $options->{nextStart} || 1; + + my @where; + push @where, "$timecol >= '$dates->{from}'" if $dates->{from}; + push @where, "$timecol <= '$dates->{'until'}'" if $dates->{'until'}; + push @where, "__ID__ >= $start"; + + my $where = join ' AND ', @where; + + if ($type eq 'article') { + $where =~ s/__ID__/stoid/; + $records = $reader->sqlSelectAll( + 'stoid', 'stories', $where, + "ORDER BY stoid LIMIT " . ($limit + 1) + ) || []; + } + + for my $i (0 .. $limit-1) { + my $record = $records->[$i] or last; + my $identifier = $self->_create_identifier({ type => $type, id => $record->[0] }); + push @return, $self->_get_identifier($identifier); + } + + my $next = $records->[$limit] ? $records->[$limit][0] : 0; + return \@return, $next; +} + +sub _print_resumptionToken { + my($self, $options, $next) = @_; + return unless $next; + my $xml; + + my $resumptionToken = "nextStart=$next"; + for my $name (qw(metadataPrefix set from until)) { + my $value = strip_attribute($options->{args}{$name}); + $resumptionToken .= "&$name=$value" if $value; + } + + $xml = sprintf <encode($resumptionToken, 'link'); + %s +EOT + + return $xml; +} + +sub _parse_resumptionToken { + my($self, $resumptionToken) = @_; + + my(%rt_args, $error); + + my @pairs = split /&/, $resumptionToken; + return unless @pairs; + + for my $pair (@pairs) { + my($name, $value) = split /=/, $pair, 2; + if ($name =~ /^(?:metadataPrefix|set|from|until|nextStart)$/) { + $rt_args{$name} = $value; + } else { + return; + } + } + + return \%rt_args; +} + +1; + +__END__ + + +=head1 SEE ALSO + +Slash(3), Slash::XML(3), L. + +=head1 VERSION + +$Id: OAI.pm,v 1.1 2006/07/12 11:41:52 sugi Exp $ Index: slashjp/plugins/OAI/PLUGIN diff -u /dev/null slashjp/plugins/OAI/PLUGIN:1.1 --- /dev/null Wed Jul 12 20:41:52 2006 +++ slashjp/plugins/OAI/PLUGIN Wed Jul 12 20:41:52 2006 @@ -0,0 +1,4 @@ +# $Id: PLUGIN,v 1.1 2006/07/12 11:41:52 sugi Exp $ +name=OAI +description="Open Archives Initiative" +htdocs=oai.pl Index: slashjp/plugins/OAI/oai.pl diff -u /dev/null slashjp/plugins/OAI/oai.pl:1.1 --- /dev/null Wed Jul 12 20:41:52 2006 +++ slashjp/plugins/OAI/oai.pl Wed Jul 12 20:41:52 2006 @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: oai.pl,v 1.1 2006/07/12 11:41:52 sugi Exp $ + +use strict; +use Slash 2.003; # require Slash 2.3.x +use Slash::Constants qw(:web); +use Slash::Display; +use Slash::Utility; +use Slash::XML; +use vars qw($VERSION); + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + + +sub main { + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $gSkin = getCurrentSkin(); + + my $allowed = 1; + if ($constants->{oai_allowed_ip} && $ENV{GATEWAY_INTERFACE}) { + $allowed = 0; + for my $ip (split /\|/, $constants->{oai_allowed_ip}) { + $allowed = 1, last if $user->{hostip} eq $ip; + } + } + + if (!$allowed) { + redirect("$gSkin->{rootdir}/"); + return; + } + + my $verb = $form->{verb}; + my %args; + for (keys %$form) { + next if /^(?:verb|query_apache)$/; + $args{$_} = $form->{$_}; + } + + xmlDisplay('OAI', { + verb => $verb, + args => \%args + }); +} + +createEnvironment(); +main(); + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:52 +0900 Subject: [Slashdotjp-dev 454] CVS update: slashjp/plugins/Page/templates Message-ID: <20060712114152.002CB2AC0EB@users.sourceforge.jp> Index: slashjp/plugins/Page/templates/data;page;default diff -u slashjp/plugins/Page/templates/data;page;default:1.2 slashjp/plugins/Page/templates/data;page;default:1.3 --- slashjp/plugins/Page/templates/data;page;default:1.2 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/Page/templates/data;page;default Wed Jul 12 20:41:52 2006 @@ -39,7 +39,7 @@ [% CASE 'readmore' %] [% returnme.data_constant = 1 %] - Read More... + Read More... [% CASE 'bytes' %] [% returnme.data_constant = 1 %] @@ -50,14 +50,14 @@ words in story [% CASE 'comments' %] - [% IF cc.0 -%] -[% cc.0.1 %] of + [% IF cc.0 -%] +[% cc.0.1 %] of [%- END -%] -[% cc.1.1 %] comment[% cc.3 != 1 ? 's' : '' %] +[% cc.1.1 %] comment[% cc.3 != 1 ? 's' : '' %] [% END %] __seclev__ 10000 __version__ -$Id: data;page;default,v 1.2 2004/12/31 12:37:12 oliver Exp $ +$Id: data;page;default,v 1.3 2006/07/12 11:41:52 sugi Exp $ Index: slashjp/plugins/Page/templates/index;page;default diff -u slashjp/plugins/Page/templates/index;page;default:1.2 slashjp/plugins/Page/templates/index;page;default:1.3 --- slashjp/plugins/Page/templates/index;page;default:1.2 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/Page/templates/index;page;default Wed Jul 12 20:41:52 2006 @@ -14,10 +14,7 @@ index __template__ - - - - - - -

    [% PROCESS titlebar title="WHAT'S NEW" %] [% misc.count = 3; @@ -28,8 +25,8 @@ [% END; %] - [ Suggest news ]
    - [ What's old? ] + [ Suggest news ]
    + [ What's old? ]
    @@ -61,15 +58,13 @@ %] - [ Older news ]
    - [ Suggest news ] + [ Older news ]
    + [ Suggest news ]
    -

    +

    [% PROCESS titlebar title="CALENDAR" %] [% @@ -86,13 +81,13 @@ FOREACH event=myevents; %] - - [% event.title %]
    + + [% event.title %]
    [% event.begin %] - [% event.end %]

    [% END; END; %] - [ Suggest an event ] + [ Suggest an event ] @@ -108,7 +103,7 @@ [% END; %] - [ Older features ] + [ Older features ] @@ -120,7 +115,7 @@ [% story.widget %] [% END; %] - [ Past opinions ] + [ Past opinions ] @@ -152,13 +147,13 @@

  • - + [% IF discussion.title.defined && discussion.title.length %] [% discussion.title %] [% ELSE %] untitled [% END %] - + [% END %] @@ -169,11 +164,7 @@ -
  • - __seclev__ 10000 __version__ -$Id: index;page;default,v 1.2 2004/12/31 12:37:12 oliver Exp $ +$Id: index;page;default,v 1.3 2006/07/12 11:41:52 sugi Exp $ Index: slashjp/plugins/Page/templates/storyTitleOnly;page;default diff -u slashjp/plugins/Page/templates/storyTitleOnly;page;default:1.3 slashjp/plugins/Page/templates/storyTitleOnly;page;default:1.4 --- slashjp/plugins/Page/templates/storyTitleOnly;page;default:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/Page/templates/storyTitleOnly;page;default Wed Jul 12 20:41:52 2006 @@ -20,4 +20,4 @@ __seclev__ 100 __version__ -$Id: storyTitleOnly;page;default,v 1.3 2004/12/31 12:37:12 oliver Exp $ +$Id: storyTitleOnly;page;default,v 1.4 2006/07/12 11:41:52 sugi Exp $ Index: slashjp/plugins/Page/templates/storylink;page;default diff -u slashjp/plugins/Page/templates/storylink;page;default:1.1 slashjp/plugins/Page/templates/storylink;page;default:1.2 --- slashjp/plugins/Page/templates/storylink;page;default:1.1 Fri Dec 24 05:13:41 2004 +++ slashjp/plugins/Page/templates/storylink;page;default Wed Jul 12 20:41:52 2006 @@ -15,4 +15,4 @@ __seclev__ 10000 __version__ -$Id: storylink;page;default,v 1.1 2004/12/23 20:13:41 oliver Exp $ +$Id: storylink;page;default,v 1.2 2006/07/12 11:41:52 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:52 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:52 +0900 Subject: [Slashdotjp-dev 455] CVS update: slashjp/plugins/Page Message-ID: <20060712114152.CF8482AC103@users.sourceforge.jp> Index: slashjp/plugins/Page/PLUGIN diff -u slashjp/plugins/Page/PLUGIN:1.2 slashjp/plugins/Page/PLUGIN:1.3 --- slashjp/plugins/Page/PLUGIN:1.2 Fri Dec 24 05:13:40 2004 +++ slashjp/plugins/Page/PLUGIN Wed Jul 12 20:41:52 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:40 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:52 sugi Exp $ name=Page description="Alternative index page for sites" htdoc=page.pl Index: slashjp/plugins/Page/Page.pm diff -u slashjp/plugins/Page/Page.pm:1.3 slashjp/plugins/Page/Page.pm:1.4 --- slashjp/plugins/Page/Page.pm:1.3 Fri Dec 31 21:37:11 2004 +++ slashjp/plugins/Page/Page.pm Wed Jul 12 20:41:52 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Page.pm,v 1.3 2004/12/31 12:37:11 oliver Exp $ +# $Id: Page.pm,v 1.4 2006/07/12 11:41:52 sugi Exp $ package Slash::Page; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; ################################################################# # Ok, so we want a nice module to do the front page and utilise Index: slashjp/plugins/Page/page.pl diff -u slashjp/plugins/Page/page.pl:1.3 slashjp/plugins/Page/page.pl:1.4 --- slashjp/plugins/Page/page.pl:1.3 Fri Dec 31 21:37:11 2004 +++ slashjp/plugins/Page/page.pl Wed Jul 12 20:41:52 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: page.pl,v 1.3 2004/12/31 12:37:11 oliver Exp $ +# $Id: page.pl,v 1.4 2006/07/12 11:41:52 sugi Exp $ use strict; use Slash; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:53 +0900 Subject: [Slashdotjp-dev 456] CVS update: slashjp/plugins/PollBooth Message-ID: <20060712114153.3753B2AC0F4@users.sourceforge.jp> Index: slashjp/plugins/PollBooth/Makefile.PL diff -u slashjp/plugins/PollBooth/Makefile.PL:1.1.1.1 slashjp/plugins/PollBooth/Makefile.PL:1.2 --- slashjp/plugins/PollBooth/Makefile.PL:1.1.1.1 Wed Jan 28 06:55:05 2004 +++ slashjp/plugins/PollBooth/Makefile.PL Wed Jul 12 20:41:53 2006 @@ -5,5 +5,8 @@ WriteMakefile( 'NAME' => 'Slash::PollBooth', 'VERSION_FROM' => 'PollBooth.pm', # finds $VERSION - 'PM' => { 'PollBooth.pm' => '$(INST_LIBDIR)/PollBooth.pm' }, + 'PM' => { + 'PollBooth.pm' => '$(INST_LIBDIR)/PollBooth.pm', + 'ResKey.pm' => '$(INST_LIBDIR)/PollBooth/ResKey.pm', + }, ); Index: slashjp/plugins/PollBooth/PLUGIN diff -u slashjp/plugins/PollBooth/PLUGIN:1.2 slashjp/plugins/PollBooth/PLUGIN:1.3 --- slashjp/plugins/PollBooth/PLUGIN:1.2 Fri Dec 24 05:13:41 2004 +++ slashjp/plugins/PollBooth/PLUGIN Wed Jul 12 20:41:53 2006 @@ -1,9 +1,10 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:41 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:53 sugi Exp $ name=PollBooth description="PollBooth" mysql_schema=mysql_schema mysql_dump=mysql_dump htdoc=pollBooth.pl +css=polls.css template=templates/data;pollBooth;default template=templates/editpoll;pollBooth;default template=templates/listpolls;pollBooth;default Index: slashjp/plugins/PollBooth/PollBooth.pm diff -u slashjp/plugins/PollBooth/PollBooth.pm:1.3 slashjp/plugins/PollBooth/PollBooth.pm:1.4 --- slashjp/plugins/PollBooth/PollBooth.pm:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/PollBooth.pm Wed Jul 12 20:41:53 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: PollBooth.pm,v 1.3 2004/12/31 12:37:12 oliver Exp $ +# $Id: PollBooth.pm,v 1.4 2006/07/12 11:41:53 sugi Exp $ package Slash::PollBooth; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; #Right, this is not needed at the moment but will be in the near future sub new { Index: slashjp/plugins/PollBooth/ResKey.pm diff -u /dev/null slashjp/plugins/PollBooth/ResKey.pm:1.1.2.1 --- /dev/null Wed Jul 12 20:41:53 2006 +++ slashjp/plugins/PollBooth/ResKey.pm Wed Jul 12 20:41:53 2006 @@ -0,0 +1,48 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: ResKey.pm,v 1.1.2.1 2006/07/12 11:41:53 sugi Exp $ + +package Slash::PollBooth::ResKey; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1.2.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + + if ($user->{is_anon} && !$constants->{allow_anon_poll_voting}) { + return(RESKEY_DEATH, ['anon', {}, 'pollBooth']); + } + + my $qid = $self->opts->{qid}; + + return(RESKEY_DEATH, ['no qid', {}, 'pollBooth']) unless $qid; + + my $pollvoter_md5 = getPollVoterHash(); + my $qid_quoted = $slashdb->sqlQuote($qid); + + # Yes, qid/id/uid is a key in pollvoters. + my($voters) = $slashdb->sqlSelect('id', 'pollvoters', + "qid=$qid_quoted AND id='$pollvoter_md5' AND uid=$user->{uid}" + ); + + if ($voters) { + return(RESKEY_DEATH, ['already voted', {}, 'pollBooth']); + } + + return RESKEY_SUCCESS; +} + +1; Index: slashjp/plugins/PollBooth/mysql_dump diff -u slashjp/plugins/PollBooth/mysql_dump:1.2 slashjp/plugins/PollBooth/mysql_dump:1.3 --- slashjp/plugins/PollBooth/mysql_dump:1.2 Fri Dec 24 05:13:41 2004 +++ slashjp/plugins/PollBooth/mysql_dump Wed Jul 12 20:41:53 2006 @@ -1,5 +1,12 @@ # -# $Id: mysql_dump,v 1.2 2004/12/23 20:13:41 oliver Exp $ +# $Id: mysql_dump,v 1.3 2006/07/12 11:41:53 sugi Exp $ # +INSERT INTO discussion_kinds (dkid, name) VALUES (NULL, 'poll'); + INSERT INTO hooks (param, class, subroutine) VALUES ('admin_save_story_success','Slash::PollBooth','createAutoPollFromStory'); + +INSERT INTO css (rel, type, media, file, title, skin, page, admin, theme, ctid, ordernum, ie_cond) VALUES ('stylesheet','text/css','screen, projection','polls.css','','','pollBooth','no','',2,0, ''); + +INSERT INTO vars (name, value, description) VALUES ('allow_anon_poll_voting', '1', 'Set this to decide whether anonymous users can vote in polls)'); + Index: slashjp/plugins/PollBooth/mysql_schema diff -u slashjp/plugins/PollBooth/mysql_schema:1.3 slashjp/plugins/PollBooth/mysql_schema:1.4 --- slashjp/plugins/PollBooth/mysql_schema:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/mysql_schema Wed Jul 12 20:41:53 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema,v 1.3 2004/12/31 12:37:12 oliver Exp $ +# $Id: mysql_schema,v 1.4 2006/07/12 11:41:53 sugi Exp $ # # Not going to install this unless the pollbooth plugin is installed Index: slashjp/plugins/PollBooth/pollBooth.pl diff -u slashjp/plugins/PollBooth/pollBooth.pl:1.3 slashjp/plugins/PollBooth/pollBooth.pl:1.4 --- slashjp/plugins/PollBooth/pollBooth.pl:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/pollBooth.pl Wed Jul 12 20:41:53 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: pollBooth.pl,v 1.3 2004/12/31 12:37:12 oliver Exp $ +# $Id: pollBooth.pl,v 1.4 2006/07/12 11:41:53 sugi Exp $ use strict; use Slash; @@ -22,15 +22,13 @@ list => \&listpolls, default => \&default, vote => \&vote, - vote_return => \&vote_return, get => \&poll_booth, preview => \&editpoll, detach => \&detachpoll, linkstory => \&link_story_to_poll ); - my $op = $form->{op}; - $op = 'default' unless $ops{$form->{op}}; + my $op = $form->{op} && $ops{$form->{op}} ? $form->{op} : 'default'; if (defined $form->{aid}) { # Only allow a short range of answer ids here. @@ -53,7 +51,7 @@ sub poll_booth { my($form) = @_; - print pollbooth($form->{'qid'}, 0, 1); + print sidebox('Poll', pollbooth($form->{'qid'}, 0, 1), 'poll', 1); } ################################################################# @@ -230,10 +228,13 @@ $question->{sid} = $form->{override_sid} if $form->{override_sid}; if ($question->{sid}) { - $story_ref = $reader->sqlSelectHashref("sid,qid,time,primaryskid,tid,displaystatus", + $story_ref = $reader->sqlSelectHashref("sid,qid,time,primaryskid,tid", "stories", "sid=" . $reader->sqlQuote($question->{sid}) ); + + $story_ref->{displaystatus} = $reader->_displaystatus($story_ref->{stoid}) if $story_ref; + if ($story_ref) { $question->{'date'} = $story_ref->{'time'}; $question->{topic} = $story_ref->{'tid'}; @@ -369,7 +370,7 @@ if ($constants->{poll_discussions}) { my $poll = $slashdb->getPollQuestion($qid); my $discussion; - if ($poll->{sid}) { + if ($form->{sid}) { # if sid lookup fails, then $discussion is empty, # and the poll's discussion is not set $discussion = $slashdb->getStory( @@ -377,6 +378,7 @@ ); } elsif (!$poll->{discussion}) { $discussion = $slashdb->createDiscussion({ + kind => 'pollbooth', title => $form->{question}, topic => $form->{topic}, approved => 1, # Story discussions are always approved -Brian @@ -398,36 +400,13 @@ } ################################################################# -sub vote_return { - my($form, $slashdb) = @_; - my $reader = getObject('Slash::DB', { db_type => 'reader' }); - - my $qid = $form->{'qid'}; - my $aid = $form->{'aid'}; - return unless $qid && $aid; - - my(%all_aid) = map { ($_->[0], 1) } - @{$reader->getPollAnswers($qid, ['aid'])}; - my $poll_open = $reader->isPollOpen($qid); - my $has_voted = $slashdb->hasVotedIn($qid); - - if ($has_voted) { - # Specific reason why can't vote. - } elsif (!$poll_open) { - # Voting is closed on this poll. - } elsif (exists $all_aid{$aid}) { - $slashdb->createPollVoter($qid, $aid); - } -} - -################################################################# sub vote { my($form, $slashdb) = @_; my $reader = getObject('Slash::DB', { db_type => 'reader' }); my $qid = $form->{'qid'}; my $aid = $form->{'aid'}; - return unless $qid; + return unless $qid && $aid; my(%all_aid) = map { ($_->[0], 1) } @{$reader->getPollAnswers($qid, ['aid'])}; @@ -441,18 +420,19 @@ my $question = $reader->getPollQuestion($qid, ['voters', 'question']); my $notes = getData('display'); - if (getCurrentUser('is_anon') && !getCurrentStatic('allow_anon_poll_voting')) { - $notes = getData('anon'); - } elsif ($aid > 0) { + if ($aid > 0) { my $poll_open = $reader->isPollOpen($qid); - my $has_voted = $slashdb->hasVotedIn($qid); - if ($has_voted) { - # Specific reason why can't vote. - $notes = getData('uid_voted'); - } elsif (!$poll_open) { + if (!$poll_open) { # Voting is closed on this poll. $notes = getData('poll_closed'); + } + + my $reskey = getObject('Slash::ResKey'); + my $rkey = $reskey->key('pollbooth', { qid => $qid }); + + if (!$rkey->createuse) { + $notes = $rkey->errstr; } elsif (exists $all_aid{$aid}) { $notes = getData('success', { aid => $aid }); $slashdb->createPollVoter($qid, $aid); @@ -498,11 +478,23 @@ ################################################################# sub listpolls { - my($form) = @_; + my($form, $slashdb, $constants) = @_; my $reader = getObject('Slash::DB', { db_type => 'reader' }); my $min = $form->{min} || 0; my $type = $form->{type}; my $questions = $reader->getPollQuestionList($min, { type => $type }); + my $gSkin = getCurrentSkin(); + my $opts = (); + $opts->{type} = $form->{type}; + $opts->{section} = $gSkin->{skid}; + + my $section = $gSkin->{name}; + if ($gSkin->{skid} == $constants->{mainpage_skid}) { + $opts->{section} = ''; + } + + $questions = $reader->getPollQuestionList($min, $opts); + my $sitename = getCurrentStatic('sitename'); # Just me, but shouldn't title be in the template? Index: slashjp/plugins/PollBooth/polls.css diff -u /dev/null slashjp/plugins/PollBooth/polls.css:1.1.2.1 --- /dev/null Wed Jul 12 20:41:53 2006 +++ slashjp/plugins/PollBooth/polls.css Wed Jul 12 20:41:53 2006 @@ -0,0 +1,47 @@ +.bar +{ + font-weight: bold; + margin: 0 0 1em 0; + border: 1px #ddd solid; + font-size: 80%; +} + +.barAnswer +{ + font-size: 120%; + text-align: left; + margin: .5em 0 0 0; +} + +.barColor +{ + background: #aaa; + border: 1px #ddd solid; + border-bottom: 1px #555 solid; + border-right: 1px #555 solid; +} + +.barPercent +{ + padding: 0 .3em; + background: #eee; + color: #555; +} + +.barVotes +{ + padding: 0 .3em; + background: #eee; + color: #555; + white-space: nowrap; +} + +.totalVotes { float: right; } +#polls-wide li { margin: 0 0 1em 0; } +.note ul +{ + font-size: 80%; + font-family: arial, sans-serif; +} +#pollBooth .generalbody table {width: 80%; margin: 0 0 1em 10%} +#pollBooth .generalbody caption {margin-left: 10%} Index: slashjp/plugins/PollBooth/rebuildAutoPoll diff -u slashjp/plugins/PollBooth/rebuildAutoPoll:1.2 slashjp/plugins/PollBooth/rebuildAutoPoll:1.3 --- slashjp/plugins/PollBooth/rebuildAutoPoll:1.2 Fri Dec 24 05:13:41 2004 +++ slashjp/plugins/PollBooth/rebuildAutoPoll Wed Jul 12 20:41:53 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: rebuildAutoPoll,v 1.2 2004/12/23 20:13:41 oliver Exp $ +# $Id: rebuildAutoPoll,v 1.3 2006/07/12 11:41:53 sugi Exp $ use strict; use File::Basename; @@ -13,7 +13,7 @@ use vars qw( $slashdb $werder $constants $junk ); -(my $VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +(my $VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; my $PROGNAME = basename($0); my %opts; @@ -78,7 +78,7 @@ $PROGNAME $VERSION This code is a part of Slash, and is released under the GPL. -Copyright 1997-2004 by Open Source Development Network. See README +Copyright 1997-2005 by Open Source Technology Group. See README and COPYING for more information, or see http://slashcode.com/. EOT From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:53 +0900 Subject: [Slashdotjp-dev 457] CVS update: slashjp/plugins/PollBooth/templates Message-ID: <20060712114153.6CBEF2AC00E@users.sourceforge.jp> Index: slashjp/plugins/PollBooth/templates/data;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/data;pollBooth;default:1.3 slashjp/plugins/PollBooth/templates/data;pollBooth;default:1.4 --- slashjp/plugins/PollBooth/templates/data;pollBooth;default:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/data;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -32,17 +32,12 @@ Story is already attatched to a different poll. Please detach poll from that story before saving. [% CASE 'invalid' %] [% returnme.data_constant = 1 %] - Invalid poll!
    + Invalid poll!
    [% CASE 'display' %] [% returnme.data_constant = 1 %] Displaying poll results. -[% CASE 'anon' %] - [% returnme.data_constant = 1 %] - You may not vote anonymously. Please - log in. - [% CASE 'uid_voted' %] [% user.nickname | strip_literal %] at [% env.remote_addr %] has already voted. [% IF env.http_x_forwarded_for %] @@ -67,9 +62,31 @@ [% returnme.data_constant = 1 %] You must provide one or more answers. +[% CASE 'slashbox_head' %] + [% returnme.data_constant = 1 %] +
    + +[% CASE 'slashbox_foot' %] + [% returnme.data_constant = 1 %] +
    + +[%# for ResKeys %] +[% CASE 'anon' %] + [% returnme.data_constant = 1 %] + You may not vote anonymously. Please + log in. + +[% CASE 'no qid' %] + [% returnme.data_constant = 1 %] + The poll ID is missing. + +[% CASE 'already voted' %] + [% returnme.data_constant = 1 %] + You've already voted. + [% END %] __seclev__ 10000 __version__ -$Id: data;pollBooth;default,v 1.3 2004/12/31 12:37:12 oliver Exp $ +$Id: data;pollBooth;default,v 1.4 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/detachpoll;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/detachpoll;pollBooth;default:1.2 slashjp/plugins/PollBooth/templates/detachpoll;pollBooth;default:1.3 --- slashjp/plugins/PollBooth/templates/detachpoll;pollBooth;default:1.2 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/detachpoll;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -17,17 +17,17 @@ __template__ [% PROCESS titlebar width='100%' %] [% IF warning.no_sid %] - No story sid given--could not complete operation. + No story sid given--could not complete operation. [% ELSIF warning.no_sid_qid_match %] - Warning: The poll qid you specified ('[% qid %]') does not appear to be currently attached to the story sid specified ('[% sid %]'). This could mean that the story doesn't have a poll attached to it or is linked to a different poll.

    If you're sure you want to detach any polls currently connected to this story click continue. + Warning: The poll qid you specified ('[% qid %]') does not appear to be currently attached to the story sid specified ('[% sid %]'). This could mean that the story doesn't have a poll attached to it or is linked to a different poll.

    If you're sure you want to detach any polls currently connected to this story click continue. [% ELSE %] - Poll detached from story successfully.
    - You can now edit or view the story.

    + Poll detached from story successfully.
    + You can now edit or view the story.

    [% IF qid %] - You can also continue on edit or view the poll that was attached to this story.
    + You can also continue on edit or view the poll that was attached to this story.
    [% END %] [% END %] __version__ -$Id: detachpoll;pollBooth;default,v 1.2 2004/12/31 12:37:12 oliver Exp $ +$Id: detachpoll;pollBooth;default,v 1.3 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/editpoll;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/editpoll;pollBooth;default:1.3 slashjp/plugins/PollBooth/templates/editpoll;pollBooth;default:1.4 --- slashjp/plugins/PollBooth/templates/editpoll;pollBooth;default:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/editpoll;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -18,77 +18,86 @@ __name__ editpoll __template__ -[% PROCESS titlebar width='100%' %] -[% USE Slash %] - -
    -
    - [% IF warning.invalid_sid %]Story ID specified does not exist invalid
    [% END %] - [% IF warning.attached_to_other %]Story is already attached to another poll -- detach poll from that story before attaching this one
    [% END %] +[% IF pollbooth %] +
    + [% PROCESS sidebox contents=poll %] +
    +
    +[% ELSE %] +
    +[% END %] + [% PROCESS titlebar %] +
    + + Poll Edit Page +
    + [% IF warning.invalid_sid %]Story ID specified does not exist invalid
    [% END %] + [% IF warning.attached_to_other %]Story is already attached to another poll -- detach poll from that story before attaching this one
    [% END %] [% PROCESS formLabel value => "The Question" comment => "followed by the total number of voters so far" %] - -
    + +
    [% PROCESS formLabel value => "Poll Section" comment => "what section this will be visible in" %] [% skins = Slash.db.getDescriptions('skins') %] [% IF story %] - [% skins.${question.primaryskid}.title %] *
    - + [% skins.${question.primaryskid}.title %] *
    + [% ELSE %] - [% Slash.createSelect('primaryskid', skins, question.primaryskid, 1) %] + [% primaryskid_val = question.primaryskid.defined ? question.primaryskid : constants.mainpage_skid %] + [% Slash.createSelect('primaryskid', skins, primaryskid_val, 1, 0, 1) %] [% END %] [% PROCESS formLabel value => "Poll Topic" comment => "" %] [% DEFAULT question.topic=constants.discussion_default_topic %] [% IF story %] - [% topics.${question.topic} %] *
    - + [% topics.${question.topic} %] *
    + [% ELSE %] [% Slash.createSelect('topic', topics, question.topic, 1, 0 ,1) %] [% END %] [% polltype.section = "SlashBox Section Poll"; polltype.story = "Story-Related Poll"; polltype.nodisplay = "Never Display" %] [% PROCESS formLabel value => "Poll Type" comment => "" %] [% IF story %] - [% polltype.${question.polltype} %] *
    - + [% polltype.${question.polltype} %] *
    + [% ELSE %] [% Slash.createSelect('polltype', polltype, question.polltype, 1) %] [% END %] -
    -Never Display - Poll won't display to regular users until type is changed
    -SlashBox Section Poll - Poll will show up on the side for a given section
    -Story Related Display - Poll is displayed on the specified story's page
    -
    +
    + Never Display - Poll won't display to regular users until type is changed
    + SlashBox Section Poll - Poll will show up on the side for a given section
    + Story Related Display - Poll is displayed on the specified story's page
    +
    + [% PROCESS formLabel value => "Poll Time" comment => "choose a time in the future if you want to delay this poll's appearance" %] - [% IF story %]*[% END %]
    + [% IF story %]*[% END %]
    [% PROCESS formLabel value => "The Answers" comment => "voters" %] [% FOREACH n = [0 .. 7] %] - -
    + +
    [% END %] - + [% PROCESS formLabel value => "Story ID" comment => "if this matches a story's ID, it will appear on the story's page" %] - [% IF question.sid %]Related story [% END %] [% IF question.sid && story && qid %]| Detach Poll from Story[% END %]
    - (time, section, topic, and polltype will be set based on related story's settings)
    + [% IF question.sid %]Related story [% END %] [% IF question.sid && story && qid %]| Detach Poll from Story[% END %]
    +
    + Time, section, topic, and polltype will be set based on related story's settings
    [% IF story %] - *These values set from related story
    + *These values set from related story
    [% END %] +
    - - - -[% IF pollbooth %] -
    - [% pollbooth %] -[% END %] -
    - + + + + + + __seclev__ 10000 __version__ -$Id: editpoll;pollBooth;default,v 1.3 2004/12/31 12:37:12 oliver Exp $ +$Id: editpoll;pollBooth;default,v 1.4 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/linkstory;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/linkstory;pollBooth;default:1.2 slashjp/plugins/PollBooth/templates/linkstory;pollBooth;default:1.3 --- slashjp/plugins/PollBooth/templates/linkstory;pollBooth;default:1.2 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/linkstory;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -17,29 +17,29 @@ 10000 __template__ [% PROCESS titlebar %] -

    Click the correct link to choose which poll you would like to attach to the story you've selected. You +

    Click the correct link to choose which poll you would like to attach to the story you've selected. You can also use the form below to select the poll qid you like to attach the story to. - +
    [% FOREACH question = questions %] - - - - + + + + [% END %] - - -
    - [% question.1 %] - - Attach poll to story -
    + [% question.1 %] + + Attach poll to story +
    -
    - - - Poll qid to attach story to: - -
    -
    + + +

    + + + Poll qid to attach story to: + +
    + + __version__ -$Id: linkstory;pollBooth;default,v 1.2 2004/12/31 12:37:12 oliver Exp $ +$Id: linkstory;pollBooth;default,v 1.3 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/listpolls;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/listpolls;pollBooth;default:1.3 slashjp/plugins/PollBooth/templates/listpolls;pollBooth;default:1.4 --- slashjp/plugins/PollBooth/templates/listpolls;pollBooth;default:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/listpolls;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -18,50 +18,57 @@ __name__ listpolls __template__ -[% PROCESS titlebar %] - - - - - - -
    - [% FOREACH question = questions %] - [% question.1 %] on [% Slash.timeCalc(question.2, '%B %o, %Y') %] with [% question.3 %] votes and [% question.4 %] comments. +
    +[% Slash.sidebox( + Slash.db.getBlock('poll', 'title'), + Slash.pollbooth('_currentqid', 1, 0), + 'poll', + 1); +%] +
    +
    + [% PROCESS titlebar %] +
    + [% skins = Slash.db.getSkins %] +
      + [% FOREACH question = questions %] +
    • [% question.1 %] on [% Slash.timeCalc(question.2, '%B %o, %Y') %]
      + [% question.3 %] votes and [% question.4 %] comments. [% IF user.is_admin %] [% SWITCH question.5 %] - [% CASE 'story' %] - (story) - [% CASE 'section' %] - (section) - [% CASE 'nodisplay' %] - (nd) - [% END %] - [% IF question.6 %](future)[% END %] - (Edit) - (Delete) - - [% END %] -
      - [% IF type == "story" %] -   ·[% question.8 %] -
      + [% CASE 'story' %] + (story) + [% CASE 'section' %] + (section) + [% CASE 'nodisplay' %] + (nd) + [% END %] + [% IF question.6 %] + (future) + [% END %] + (Edit) + (Delete) [% END %] +
      +
    • + [% IF type == "story" %] +
    • + [% question.8 %] +
    • [% END %] -
    - [% Slash.fancybox( - constants.fancyboxwidth, - Slash.db.getBlock('poll', 'title'), - Slash.pollbooth('_currentqid', 1), - 0, - 1 - ); %] -
    + [% END %] + -

    More Polls -
    Submit Poll +

    + + More Polls
    + Submit Poll +
    +

    + + __seclev__ 10000 __version__ -$Id: listpolls;pollBooth;default,v 1.3 2004/12/31 12:37:12 oliver Exp $ +$Id: listpolls;pollBooth;default,v 1.4 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/pollbooth;misc;default diff -u slashjp/plugins/PollBooth/templates/pollbooth;misc;default:1.3 slashjp/plugins/PollBooth/templates/pollbooth;misc;default:1.4 --- slashjp/plugins/PollBooth/templates/pollbooth;misc;default:1.3 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/pollbooth;misc;default Wed Jul 12 20:41:53 2006 @@ -8,8 +8,6 @@ * qid = question ID * has_activated = has this poll become active? * poll_open = is this poll still open? -* has_voted = has this user already voted? -* can_vote = can this user still vote? * voters = number of voters * comments = number of comments * primaryskid = primaryskid @@ -26,52 +24,62 @@ pollbooth __template__ [% IF has_activated or user.is_admin %] -[% IF user.is_admin %] - [% IF !has_activated %] - (Poll not yet active)
    - [% END %] -[% END %] -[% IF !can_vote %] - - [% question %] - - [% FOREACH ans = answers %] -
    · [% ans.answer %] ([% ans.votes %]) - [% END %] - -

    [% IF has_voted %](You've already voted.)[% ELSIF !poll_open %](Poll is closed.)[% END %]
    - [ Results | - Polls ]
    - Comments:[% comments %] | Votes:[% voters %] - -[% ELSE %] - -

    - [%- IF returnto -%] - - - [%- END -%] - - [% IF user.currentSkin %] - + [% IF user.is_admin %] + [% IF !has_activated %] + (Poll not yet active.)
    [% END %] - [% question %] - - [% FOREACH ans = answers %] -
    [% ans.answer | strip_html %] [% END %] -
    - [ Results | - Polls ]
    - Comments:[% comments %] | Votes:[% voters %] -
    + [% can_vote = poll_open ? 1 : 0 %] -[% END %] + [% IF env.script_name && can_vote; + reskey = Slash.getObject('Slash::ResKey'); + rkey = reskey.key('pollbooth', { qid => qid }); + IF !rkey.create; # didn't work, bail + can_vote = 0; + END; + ELSE; + rkey = ''; + END; + %] + + [% IF !can_vote %] + [% question | strip_literal %] + [% FOREACH ans = answers %] +
  • [% ans.answer | strip_literal %] ([% ans.votes %])
  • + [% END %] + +

    [% IF rkey && rkey.errstr %]([% rkey.errstr %])[% ELSIF !poll_open %](Poll is closed.)[% END %]
    + [ Results | + Polls ]
    + Comments:[% comments %] | Votes:[% voters %] + + [% ELSE %] + +

    +
    + Poll + + [% IF user.currentSkin %] + + [% END %] + [% question | strip_literal %] + + [% FOREACH ans = answers %] +
    [% ans.answer | strip_literal %] + [% END %] + +
    + [% IF env.gateway_interface; PROCESS reskey_tag; END %] + [ Results | + Polls ]
    + Comments:[% comments %] | Votes:[% voters %] +
    +
    + [% END %] [% END %] __seclev__ 10000 __version__ -$Id: pollbooth;misc;default,v 1.3 2004/12/31 12:37:12 oliver Exp $ +$Id: pollbooth;misc;default,v 1.4 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/savepoll;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/savepoll;pollBooth;default:1.1.1.1 slashjp/plugins/PollBooth/templates/savepoll;pollBooth;default:1.2 --- slashjp/plugins/PollBooth/templates/savepoll;pollBooth;default:1.1.1.1 Wed Jan 28 06:55:06 2004 +++ slashjp/plugins/PollBooth/templates/savepoll;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -17,11 +17,11 @@ [% aid = "aid$n" %] [% votes = "votes$n" %] [% IF form.$aid %] -
    Answer [% n %] '[% form.$aid %]' [% form.$votes %] +
    Answer [% n %] '[% form.$aid %]' [% form.$votes %] [% END %] [% END %] __seclev__ 10000 __version__ -$Id: savepoll;pollBooth;default,v 1.1.1.1 2004/01/27 21:55:06 oliver Exp $ +$Id: savepoll;pollBooth;default,v 1.2 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/PollBooth/templates/vote;pollBooth;default diff -u slashjp/plugins/PollBooth/templates/vote;pollBooth;default:1.2 slashjp/plugins/PollBooth/templates/vote;pollBooth;default:1.3 --- slashjp/plugins/PollBooth/templates/vote;pollBooth;default:1.2 Fri Dec 31 21:37:12 2004 +++ slashjp/plugins/PollBooth/templates/vote;pollBooth;default Wed Jul 12 20:41:53 2006 @@ -18,55 +18,47 @@ __name__ vote __template__ -
    - -[% FOR poll = pollitems %] - [% answer = poll.0 - imagewidth = poll.1 - votes = poll.2 - percent = poll.3 - %] - - - - - -[% END %] - - -
    -[% PROCESS titlebar %] -[% notes %]
    [% answer %]  [% percent %]% - [% votes %] / - [% percent %]% -
    - [% voters %] total votes. -

    +

    + [% PROCESS titlebar %] +
    +
    + [% notes %] +
    + [% FOR poll = pollitems %] + [% answer = poll.0 + imagewidth = poll.1 + votes = poll.2 + percent = poll.3 + %] + + + + [% IF percent > 0 %] + + [% END %] + + + +
    [% answer %]
     [% percent %]%[% votes %] votes
    + [% END %] + [% voters %] total votes. +
    [ - Voting Booth | - Other Polls | - Back Home + Voting Booth | + Other Polls | + Back Home ] -
    -

    -

  • Don't complain about lack of options. You've got to pick a few - when you do multiple choice. Those are the breaks. - -
  • Feel free to suggest poll ideas if you're feeling creative. - I'd strongly suggest reading the past polls first. - -
  • This whole thing is wildly inaccurate. Rounding errors, - ballot stuffers, dynamic IPs, firewalls. If you're using these - numbers to do anything important, you're insane. -

    -
  • - +
    +
      +
    • Don't complain about lack of options. You've got to pick a few when you do multiple choice. Those are the breaks.
    • +
    • Feel free to suggest poll ideas if you're feeling creative. I'd strongly suggest reading the past polls first.
    • +
    • This whole thing is wildly inaccurate. Rounding errors, ballot stuffers, dynamic IPs, firewalls. If you're using these numbers to do anything important, you're insane.
    • +
    +
    + + __seclev__ 10000 __version__ -$Id: vote;pollBooth;default,v 1.2 2004/12/31 12:37:12 oliver Exp $ +$Id: vote;pollBooth;default,v 1.3 2006/07/12 11:41:53 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:53 +0900 Subject: [Slashdotjp-dev 458] CVS update: slashjp/plugins/Print/templates Message-ID: <20060712114153.C74DA2AC0EB@users.sourceforge.jp> Index: slashjp/plugins/Print/templates/dispStory;print;default diff -u slashjp/plugins/Print/templates/dispStory;print;default:1.2 slashjp/plugins/Print/templates/dispStory;print;default:1.3 --- slashjp/plugins/Print/templates/dispStory;print;default:1.2 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Print/templates/dispStory;print;default Wed Jul 12 20:41:53 2006 @@ -20,36 +20,36 @@ 10000 __template__ [% UNLESS form.nohtml; - topic = "$topic.alttext"; + topic = "$topic.alttext"; ELSE; topic = topic.alttext; END -%] - - - - - +
    Title    [% story.title %]
    Date    [% story.storytime %]
    Author    [% author.nickname | strip_literal %]
    Topic    [% topic %]
    + + + + [% IF constants.use_dept -%] - + [% END -%] -
    Title    [% story.title %]
    Date    [% story.storytime %]
    Author    [% author.nickname | strip_literal %]
    Topic    [% topic %]
    from the [% story.dept %] dept.
    from the [% story.dept %] dept.
    -[% gSkin.absolutedir -%]/article.pl?sid=[% story.sid %] + +[% gSkin.absolutedir -%]/article.pl?sid=[% story.sid %] -

    [% Slash.parseSlashizedLinks(story.introtext) %]

    +

    [% Slash.parseSlashizedLinks(story.introtext) %]

    [% IF story.bodytext -%] -

    [% Slash.parseSlashizedLinks(story.bodytext) %]

    +

    [% Slash.parseSlashizedLinks(story.bodytext) %]

    [% END -%] [% IF links.size -%] - - - -
    Links

    + + + +
    Links

    -
      [% FOR l=links -%] -
    1. "[% l.1 %]" - [% l.0 %]
    2. -[% END %]
    +
      [% FOR l=links -%] +
    1. "[% l.1 %]" - [% l.0 %]
    2. +[% END %]
    [% END -%] __version__ -$Id: dispStory;print;default,v 1.2 2004/12/31 12:37:13 oliver Exp $ +$Id: dispStory;print;default,v 1.3 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/Print/templates/footer;print;default diff -u slashjp/plugins/Print/templates/footer;print;default:1.2 slashjp/plugins/Print/templates/footer;print;default:1.3 --- slashjp/plugins/Print/templates/footer;print;default:1.2 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Print/templates/footer;print;default Wed Jul 12 20:41:53 2006 @@ -35,22 +35,22 @@ sitename = "$constants.sitename ($absdir)"; END -%] -
    -
    © Copyright [% Slash.timeCalc(Slash.db.getTime, '%Y') %] -- [% constants.sitepublisher %], All Rights Reserved
    -
    +
    +
    © Copyright [% Slash.timeCalc(Slash.db.getTime, '%Y') %] +- [% constants.sitepublisher %], All Rights Reserved
    +
    -

    -printed from [% sitename %], [% url %] on [% time %] -

    +

    +printed from [% sitename %], [% url %] on [% time %] +

    [% IF form.auto -%] + [% END -%] - - + + __version__ -$Id: footer;print;default,v 1.2 2004/12/31 12:37:13 oliver Exp $ +$Id: footer;print;default,v 1.3 2006/07/12 11:41:53 sugi Exp $ Index: slashjp/plugins/Print/templates/header;print;default diff -u slashjp/plugins/Print/templates/header;print;default:1.2 slashjp/plugins/Print/templates/header;print;default:1.3 --- slashjp/plugins/Print/templates/header;print;default:1.2 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Print/templates/header;print;default Wed Jul 12 20:41:53 2006 @@ -13,12 +13,12 @@ __seclev__ 10000 __template__ - - + + -

    [% constants.sitename %]
    -[% constants.slogan %]
    -[% gSkin.absolutedir %]/

    +

    [% constants.sitename %]
    +[% constants.slogan %]
    +[% gSkin.absolutedir %]/

    [% IF constants.run_ads -%] [% END -%] __version__ -$Id: header;print;default,v 1.2 2004/12/31 12:37:13 oliver Exp $ +$Id: header;print;default,v 1.3 2006/07/12 11:41:53 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:53 +0900 Subject: [Slashdotjp-dev 459] CVS update: slashjp/plugins/PubKey Message-ID: <20060712114153.EC6942AC0F4@users.sourceforge.jp> Index: slashjp/plugins/PubKey/PLUGIN diff -u slashjp/plugins/PubKey/PLUGIN:1.2 slashjp/plugins/PubKey/PLUGIN:1.3 --- slashjp/plugins/PubKey/PLUGIN:1.2 Fri Dec 24 05:13:42 2004 +++ slashjp/plugins/PubKey/PLUGIN Wed Jul 12 20:41:53 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:42 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:53 sugi Exp $ name=PubKey description="Just allows a user's pubkey to be displayed" htdoc=pubkey.pl Index: slashjp/plugins/PubKey/pubkey.pl diff -u slashjp/plugins/PubKey/pubkey.pl:1.2 slashjp/plugins/PubKey/pubkey.pl:1.3 --- slashjp/plugins/PubKey/pubkey.pl:1.2 Fri Dec 24 05:13:42 2004 +++ slashjp/plugins/PubKey/pubkey.pl Wed Jul 12 20:41:53 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: pubkey.pl,v 1.2 2004/12/23 20:13:42 oliver Exp $ +# $Id: pubkey.pl,v 1.3 2006/07/12 11:41:53 sugi Exp $ use strict; use Slash 2.001; # require Slash 2.1 @@ -11,7 +11,7 @@ use Slash::XML; use vars qw($VERSION); -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; sub main { my $slashdb = getCurrentDB(); @@ -31,6 +31,7 @@ content_type => 'text/plain', filename => "pubkey-$uid.asc", do_etag => 1, + dis_type => 'inline', content => $content }); } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:53 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:53 +0900 Subject: [Slashdotjp-dev 460] CVS update: slashjp/plugins/Print Message-ID: <20060712114153.A37B42AC104@users.sourceforge.jp> Index: slashjp/plugins/Print/INSTALL diff -u slashjp/plugins/Print/INSTALL:1.3 slashjp/plugins/Print/INSTALL:1.4 --- slashjp/plugins/Print/INSTALL:1.3 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Print/INSTALL Wed Jul 12 20:41:53 2006 @@ -1,5 +1,5 @@ # -# $Id: INSTALL,v 1.3 2004/12/31 12:37:13 oliver Exp $ +# $Id: INSTALL,v 1.4 2006/07/12 11:41:53 sugi Exp $ # Don't forget to modify the display;article;default template to add a link to Index: slashjp/plugins/Print/PLUGIN diff -u slashjp/plugins/Print/PLUGIN:1.2 slashjp/plugins/Print/PLUGIN:1.3 --- slashjp/plugins/Print/PLUGIN:1.2 Fri Dec 24 05:13:42 2004 +++ slashjp/plugins/Print/PLUGIN Wed Jul 12 20:41:53 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:42 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:53 sugi Exp $ name=Print htdoc=print.pl image=images/print.gif Index: slashjp/plugins/Print/print.pl diff -u slashjp/plugins/Print/print.pl:1.3 slashjp/plugins/Print/print.pl:1.4 --- slashjp/plugins/Print/print.pl:1.3 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Print/print.pl Wed Jul 12 20:41:53 2006 @@ -28,9 +28,9 @@ # ISBN: 0-596-00200-2 # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: print.pl,v 1.3 2004/12/31 12:37:13 oliver Exp $ +# $Id: print.pl,v 1.4 2006/07/12 11:41:53 sugi Exp $ use strict; use HTML::TreeBuilder; @@ -39,7 +39,7 @@ use Slash::Utility; use vars qw( $VERSION ); -($VERSION) = ' $Revision: 1.3 $' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $' =~ /\$Revision:\s+([^\s]+)/; sub main { my $constants = getCurrentStatic(); @@ -99,7 +99,9 @@ # routine in admin.pl to use it instead -- pudge my @story_links; my $tree = new HTML::TreeBuilder; - $tree->parse(parseSlashizedLinks($story->{introtext} . $story->{bodytext})); + my $storytext = $story->{introtext} || ''; + $storytext .= $story->{bodytext} if defined $story->{bodytext}; + $tree->parse(processSlashTags(parseSlashizedLinks($storytext))); $tree->eof; my $links = $tree->extract_links('a'); # get "A" tags only @@ -153,9 +155,12 @@ # Thanks for the assist here, pudge! sub get_content { my($ref) = @_; - my $content; + return '' if !$ref || !ref($ref->{_content}); - $content .= (ref) ? get_content($_) : $_ for @{$ref->{_content}}; + my $content = ''; + for my $c (@{$ref->{_content}}) { + $content .= ref($c) ? get_content($c) : $c; + } return $content; } From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:54 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:54 +0900 Subject: [Slashdotjp-dev 461] CVS update: slashjp/plugins/PubKey/templates Message-ID: <20060712114154.44E912AC00E@users.sourceforge.jp> Index: slashjp/plugins/PubKey/templates/data;pubkey;default diff -u slashjp/plugins/PubKey/templates/data;pubkey;default:1.1.1.1 slashjp/plugins/PubKey/templates/data;pubkey;default:1.2 --- slashjp/plugins/PubKey/templates/data;pubkey;default:1.1.1.1 Wed Jan 28 06:55:06 2004 +++ slashjp/plugins/PubKey/templates/data;pubkey;default Wed Jul 12 20:41:54 2006 @@ -30,4 +30,4 @@ __seclev__ 10000 __version__ -$Id: data;pubkey;default,v 1.1.1.1 2004/01/27 21:55:06 oliver Exp $ +$Id: data;pubkey;default,v 1.2 2006/07/12 11:41:54 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:54 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:54 +0900 Subject: [Slashdotjp-dev 462] CVS update: slashjp/plugins/Rating Message-ID: <20060712114154.772F02AC102@users.sourceforge.jp> Index: slashjp/plugins/Rating/PLUGIN diff -u slashjp/plugins/Rating/PLUGIN:1.1 slashjp/plugins/Rating/PLUGIN:1.2 --- slashjp/plugins/Rating/PLUGIN:1.1 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Rating/PLUGIN Wed Jul 12 20:41:54 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.1 2004/12/31 12:37:13 oliver Exp $ +# $Id: PLUGIN,v 1.2 2006/07/12 11:41:54 sugi Exp $ name=Rating description="Rating" mysql_schema=mysql_schema Index: slashjp/plugins/Rating/Rating.pm diff -u slashjp/plugins/Rating/Rating.pm:1.1 slashjp/plugins/Rating/Rating.pm:1.2 --- slashjp/plugins/Rating/Rating.pm:1.1 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Rating/Rating.pm Wed Jul 12 20:41:54 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Rating.pm,v 1.1 2004/12/31 12:37:13 oliver Exp $ +# $Id: Rating.pm,v 1.2 2006/07/12 11:41:54 sugi Exp $ package Slash::Rating; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; #Right, this is not needed at the moment but will be in the near future sub new { Index: slashjp/plugins/Rating/set_disc_ratings.pl diff -u slashjp/plugins/Rating/set_disc_ratings.pl:1.1 slashjp/plugins/Rating/set_disc_ratings.pl:1.2 --- slashjp/plugins/Rating/set_disc_ratings.pl:1.1 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Rating/set_disc_ratings.pl Wed Jul 12 20:41:54 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: set_disc_ratings.pl,v 1.1 2004/12/31 12:37:13 oliver Exp $ +# $Id: set_disc_ratings.pl,v 1.2 2006/07/12 11:41:54 sugi Exp $ use strict; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:54 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:54 +0900 Subject: [Slashdotjp-dev 463] CVS update: slashjp/plugins/Relocate/templates Message-ID: <20060712114154.C14442AC109@users.sourceforge.jp> Index: slashjp/plugins/Relocate/templates/deadPage;relocate;default diff -u slashjp/plugins/Relocate/templates/deadPage;relocate;default:1.2 slashjp/plugins/Relocate/templates/deadPage;relocate;default:1.3 --- slashjp/plugins/Relocate/templates/deadPage;relocate;default:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/Relocate/templates/deadPage;relocate;default Wed Jul 12 20:41:54 2006 @@ -11,10 +11,10 @@ __name__ deadPage __template__ -

    D'oh!

    +

    D'oh!

    Sorry, the url [% link.url %] that you wished to connect to is currently down (we noticed it at [% Slash.timeCalc(link.last_seen) %].
    You might consider trying to access a cached version of it on google. __seclev__ 10000 __version__ -$Id: deadPage;relocate;default,v 1.2 2004/12/23 20:13:43 oliver Exp $ +$Id: deadPage;relocate;default,v 1.3 2006/07/12 11:41:54 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:54 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:54 +0900 Subject: [Slashdotjp-dev 464] CVS update: slashjp/plugins/Relocate Message-ID: <20060712114154.9C5AB2AC107@users.sourceforge.jp> Index: slashjp/plugins/Relocate/PLUGIN diff -u slashjp/plugins/Relocate/PLUGIN:1.2 slashjp/plugins/Relocate/PLUGIN:1.3 --- slashjp/plugins/Relocate/PLUGIN:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/Relocate/PLUGIN Wed Jul 12 20:41:54 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:43 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:54 sugi Exp $ name=Relocate description="redirect your href links" mysql_schema=mysql_schema Index: slashjp/plugins/Relocate/Relocate.pm diff -u slashjp/plugins/Relocate/Relocate.pm:1.3 slashjp/plugins/Relocate/Relocate.pm:1.4 --- slashjp/plugins/Relocate/Relocate.pm:1.3 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Relocate/Relocate.pm Wed Jul 12 20:41:54 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Relocate.pm,v 1.3 2004/12/31 12:37:13 oliver Exp $ +# $Id: Relocate.pm,v 1.4 2006/07/12 11:41:54 sugi Exp $ package Slash::Relocate; @@ -15,7 +15,7 @@ use vars qw($VERSION); use base 'Slash::DB::Utility'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $user) = @_; @@ -89,19 +89,14 @@ if ($token->[0] eq 'slash') { #Skip non HREF links next unless $token->[1]{href} && $token->[1]{type} eq 'link'; - if (!$token->[1]{id}) { - my $link = $self->create({ stoid => $stoid, url => $token->[1]{href}}); - my $href = strip_attribute($token->[1]{href}); - my $title = strip_attribute($token->[1]{title}); - $text =~ s#\Q$token->[3]\E##is; - } else { + if ($token->[1]{id}) { my $url = $self->get($token->[1]{id}, 'url'); next if $url eq $token->[1]{href}; - my $link = $self->create({ stoid => $stoid, url => $token->[1]{href}}); - my $href = strip_attribute($token->[1]{href}); - my $title = strip_attribute($token->[1]{title}); - $text =~ s#\Q$token->[3]\E##is; } + my $link = $self->create({ stoid => $stoid, url => $token->[1]{href}}); + my $href = strip_attribute($token->[1]{href}); + my $title = strip_attribute($token->[1]{title}); + $text =~ s#\Q$token->[3]\E##is; # New links to convert!!!! } else { # We ignore some types of href @@ -110,11 +105,12 @@ next if ($token->[1]{href} =~ /^mailto/i); #This allows you to have a link bypass this system next if ($token->[1]{FORCE} && $user->{is_admin}); + my $link = $self->create({ stoid => $stoid, url => $token->[1]{href}}); - my $data = $tokens->get_text("/a"); + my $data = $tokens->get_text('/a'); my $href = strip_attribute($token->[1]{href}); my $title = strip_attribute($token->[1]{title}); - $text =~ s#\Q$token->[3]$data\E#$data#is; + $text =~ s#\Q$token->[3]$data\E#$data#is; } } } Index: slashjp/plugins/Relocate/mysql_dump diff -u slashjp/plugins/Relocate/mysql_dump:1.1 slashjp/plugins/Relocate/mysql_dump:1.2 --- slashjp/plugins/Relocate/mysql_dump:1.1 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/Relocate/mysql_dump Wed Jul 12 20:41:54 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_dump,v 1.1 2004/12/23 20:13:43 oliver Exp $ +# $Id: mysql_dump,v 1.2 2006/07/12 11:41:54 sugi Exp $ # INSERT INTO vars (name, value, description) VALUES ('relocate_href2slash', 0, 'Automatically convert all A HREF tags to SLASH HREF tags, using relocate.pl.'); Index: slashjp/plugins/Relocate/mysql_schema diff -u slashjp/plugins/Relocate/mysql_schema:1.3 slashjp/plugins/Relocate/mysql_schema:1.4 --- slashjp/plugins/Relocate/mysql_schema:1.3 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Relocate/mysql_schema Wed Jul 12 20:41:54 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema,v 1.3 2004/12/31 12:37:13 oliver Exp $ +# $Id: mysql_schema,v 1.4 2006/07/12 11:41:54 sugi Exp $ # # Index: slashjp/plugins/Relocate/relocate.pl diff -u slashjp/plugins/Relocate/relocate.pl:1.3 slashjp/plugins/Relocate/relocate.pl:1.4 --- slashjp/plugins/Relocate/relocate.pl:1.3 Fri Dec 31 21:37:13 2004 +++ slashjp/plugins/Relocate/relocate.pl Wed Jul 12 20:41:54 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: relocate.pl,v 1.3 2004/12/31 12:37:13 oliver Exp $ +# $Id: relocate.pl,v 1.4 2006/07/12 11:41:54 sugi Exp $ use strict; use Slash; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:54 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:54 +0900 Subject: [Slashdotjp-dev 465] CVS update: slashjp/plugins/Remarks Message-ID: <20060712114154.EA3B92AC0F4@users.sourceforge.jp> Index: slashjp/plugins/Remarks/MANIFEST diff -u /dev/null slashjp/plugins/Remarks/MANIFEST:1.1 --- /dev/null Wed Jul 12 20:41:54 2006 +++ slashjp/plugins/Remarks/MANIFEST Wed Jul 12 20:41:54 2006 @@ -0,0 +1,4 @@ +Makefile.PL +MANIFEST +Remarks.pm +remarks.pl Index: slashjp/plugins/Remarks/Makefile.PL diff -u /dev/null slashjp/plugins/Remarks/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:54 2006 +++ slashjp/plugins/Remarks/Makefile.PL Wed Jul 12 20:41:54 2006 @@ -0,0 +1,8 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Slash::Remarks', + 'VERSION_FROM' => 'Remarks.pm', # finds $VERSION + 'PM' => { 'Remarks.pm' => '$(INST_LIBDIR)/Remarks.pm' }, +); Index: slashjp/plugins/Remarks/PLUGIN diff -u /dev/null slashjp/plugins/Remarks/PLUGIN:1.1 --- /dev/null Wed Jul 12 20:41:54 2006 +++ slashjp/plugins/Remarks/PLUGIN Wed Jul 12 20:41:54 2006 @@ -0,0 +1,7 @@ +# $Id: PLUGIN,v 1.1 2006/07/12 11:41:54 sugi Exp $ +name=Remarks +description="Remarks" +htdocs=remarks.pl +template=templates/data;remarks;default +template=templates/display;remarks;default +template=templates/config_remarks;misc;default Index: slashjp/plugins/Remarks/Remarks.pm diff -u /dev/null slashjp/plugins/Remarks/Remarks.pm:1.1 --- /dev/null Wed Jul 12 20:41:54 2006 +++ slashjp/plugins/Remarks/Remarks.pm Wed Jul 12 20:41:54 2006 @@ -0,0 +1,195 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: Remarks.pm,v 1.1 2006/07/12 11:41:54 sugi Exp $ + +package Slash::Remarks; + +=head1 NAME + +Slash::Remarks - Perl extension for Remarks + + +=head1 SYNOPSIS + + use Slash::Remarks; + + +=head1 DESCRIPTION + +LONG DESCRIPTION. + + +=head1 EXPORTED FUNCTIONS + +=cut + +use strict; +use DBIx::Password; +use Slash; +use Slash::Display; +use Slash::Utility; + +use base 'Slash::DB::Utility'; +use base 'Slash::DB::MySQL'; +use vars qw($VERSION); + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +######################################################## +sub new { + my($class, $user) = @_; + my $self = {}; + + my $plugin = getCurrentStatic('plugin'); + return unless $plugin->{'Remarks'}; + + bless($self, $class); + $self->{virtual_user} = $user; + $self->sqlConnect; + + return $self; +} + +######################################################## +sub getRemarks { + my($self, $options) = @_; + + my $max = $options->{max} || 100; + + my @where; + if ($options->{min_priority}) { + push @where, 'priority >= ' . $self->sqlQuote($options->{min_priority}); + } + if ($options->{string}) { + push @where, 'remark LIKE ' . $self->sqlQuote('%' . $options->{string} . '%'); + } + + my $remarks = $self->sqlSelectAllHashrefArray( + 'rid, uid, stoid, time, remark, type, priority', + 'remarks', + join(' AND ', @where), + "ORDER BY rid DESC LIMIT $max" + ); + + return $remarks || []; +} + +######################################################## +sub createRemark { + my($self, $remark, $options) = @_; + + my $remark_t = $self->truncateStringForCharColumn($remark, 'remarks', 'remark'); + + $self->sqlInsert('remarks', { + uid => $options->{uid} || getCurrentAnonymousCoward('uid'), + stoid => $options->{stoid} || 0, + type => $options->{type} || 'user', + priority => $options->{priority} || 0, + -time => 'NOW()', + remark => $remark_t, + }); +} + +######################################################## +sub getRemarksStarting { + my($self, $starting, $options) = @_; + return [ ] unless $starting; + + my $starting_q = $self->sqlQuote($starting); + my $type_clause = $options->{type} + ? ' AND type=' . $self->sqlQuote($options->{type}) + : ''; + + return $self->sqlSelectAllHashrefArray( + 'rid, stoid, remarks.uid, remark, karma, remarks.type', + 'remarks, users_info', + "remarks.uid=users_info.uid AND rid >= $starting_q $type_clause" + ); +} + +######################################################## +sub getUserRemarkCount { + my($self, $uid, $secs_back) = @_; + return 0 unless $uid && $secs_back; + + return $self->sqlCount( + 'remarks', + "uid = $uid + AND time >= DATE_SUB(NOW(), INTERVAL $secs_back SECOND)" + ); +} + + +######################################################## +sub displayRemarksTable { + my($self, $options) = @_; + my $user = getCurrentUser(); + $self ||= getObject('Slash::Remarks'); + $options ||= {}; + $options->{string} = $user->{remarks_filter} if $user->{remarks_filter}; + $options->{min_priority} = $user->{remarks_min_priority} if $user->{min_priority}; + $options->{max} = $user->{remarks_limit} || 10; + + my $remarks_ref = $self->getRemarks($options); + return slashDisplay('display', { + remarks_ref => $remarks_ref, + print_whole => $options->{print_whole}, + print_div => $options->{print_div}, + remarks_max => $options->{max}, + }, { Page => 'remarks', Return => 1 }); +} + +######################################################## +sub ajaxFetch { + my($slashdb, $constants, $user, $form) = @_; + my $self = getObject('Slash::Remarks'); + my $options = {}; + + $options->{max} = $form->{limit} || 30; + + if ($form->{op} eq 'remarks_create') { + $options->{print_div} = 1; + $self->createRemark($form->{remark}, { + uid => $user->{uid}, + type => 'system', + }); + } + + return $self->displayRemarksTable($options); +} + +sub ajaxFetchConfigPanel { + my($slashdb, $constants, $user, $form) = @_; + slashDisplay('config_remarks', {}, { Return => 1 }); +} + +sub ajaxConfigSave { + my($slashdb, $constants, $user, $form) = @_; + my $data = {}; + if (defined $form->{limit}) { + $data->{remarks_limit} = $form->{limit} + } + if (defined $form->{filter}) { + $data->{remarks_filter} = $form->{filter}; + } + if (defined $form->{min_priority}) { + $data->{remarks_min_priority} = $form->{min_priority}; + } + $slashdb->setUser($user->{uid}, $data) if keys %$data; + # this should be in a template -- pudge + return "Close"; +} + +1; + +__END__ + + +=head1 SEE ALSO + +Slash(3). + +=head1 VERSION + +$Id: Remarks.pm,v 1.1 2006/07/12 11:41:54 sugi Exp $ Index: slashjp/plugins/Remarks/remarks.pl diff -u /dev/null slashjp/plugins/Remarks/remarks.pl:1.1 --- /dev/null Wed Jul 12 20:41:54 2006 +++ slashjp/plugins/Remarks/remarks.pl Wed Jul 12 20:41:54 2006 @@ -0,0 +1,66 @@ +#!/usr/bin/perl +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: remarks.pl,v 1.1 2006/07/12 11:41:54 sugi Exp $ + +use strict; +use warnings; + +use Slash 2.003; # require Slash 2.3.x +use Slash::Constants qw(:web); +use Slash::Display; +use Slash::Utility; +use Slash::XML; +use vars qw($VERSION); + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + + +sub main { + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $gSkin = getCurrentSkin(); + my $remarks = getObject('Slash::Remarks'); + + if (! $user->{is_admin}) { + redirect("$gSkin->{rootdir}/"); + return; + } + + my %ops = ( + display => \&display, + save_prefs => \&save_prefs, + + default => \&display + ); + + my $op = $form->{op}; + if (!$op || !exists $ops{$op} || !$ops{$op}[ALLOWED]) { + $op = 'default'; + } + + header('Remarks', '', { admin => 1 }) or return; + + $ops{$op}->($slashdb, $constants, $user, $form, $gSkin, $remarks); + + footer(); +} + + +sub display { + my($slashdb, $constants, $user, $form, $gSkin, $remarks) = @_; + print $remarks->displayRemarksTable({ max => 30, print_whole => 1 }); +} + +sub save_prefs { + my($slashdb, $constants, $user, $form, $gSkin) = @_; + +} + +createEnvironment(); +main(); + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:55 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:55 +0900 Subject: [Slashdotjp-dev 466] CVS update: slashjp/plugins/Remarks/templates Message-ID: <20060712114155.1FCEF2AC00E@users.sourceforge.jp> Index: slashjp/plugins/Remarks/templates/config_remarks;misc;default diff -u /dev/null slashjp/plugins/Remarks/templates/config_remarks;misc;default:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/Remarks/templates/config_remarks;misc;default Wed Jul 12 20:41:55 2006 @@ -0,0 +1,23 @@ +__section__ +default +__description__ +You should describe stuff here. +__title__ +Useless title to template +__page__ +misc +__lang__ +en_US +__name__ +config_remarks +__seclev__ +10000 +__template__ +[% priority = user.remarks_min_priority || 0 %] +[% filter = user.remarks_filter || "" %] +[% limit = user.remarks_limit || 10 %] +Min Priority:
    +Filter:
    +Number to show:
    + + Index: slashjp/plugins/Remarks/templates/data;remarks;default diff -u /dev/null slashjp/plugins/Remarks/templates/data;remarks;default:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/Remarks/templates/data;remarks;default Wed Jul 12 20:41:55 2006 @@ -0,0 +1,29 @@ +__section__ +default +__description__ +Repository for random data elements. + +* value = the name of the data element to retrieve + +Each data element may have any number of other variables. +__title__ + +__page__ +remarks +__lang__ +en_US +__name__ +data +__template__ +[% SWITCH value %] + +[% CASE 'title' %] + [% returnme.data_constant = 1 %] + [% constants.sitename %] Remarks + +[% END %] + +__seclev__ +10000 +__version__ +$Id: data;remarks;default,v 1.1 2006/07/12 11:41:55 sugi Exp $ Index: slashjp/plugins/Remarks/templates/display;remarks;default diff -u /dev/null slashjp/plugins/Remarks/templates/display;remarks;default:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/Remarks/templates/display;remarks;default Wed Jul 12 20:41:55 2006 @@ -0,0 +1,54 @@ +__section__ +default +__description__ +__title__ + +__page__ +remarks +__lang__ +en_US +__name__ +display +__template__ + +[% IF print_whole %] + + + +
    +[% END; + + IF print_div || print_whole %] + + [% PROCESS ajax_reskey_tag reskey_label => 'remarks_reskey', reskey_name => 'ajax_admin' %] + +
    +[% END %] + + + + + +[% i = 1; FOREACH remark = remarks_ref; i = i == 1 ? 2 : 1 %] + + + + + + + +[% END # FOREACH %] +
    Remarks (Last Updated [% Slash.timeCalc(Slash.db.getTime, '%Y-%m-%d %H:%M:%S %Z', 0) %]) [Config]
    [% Slash.timeCalc(remark.time, '%H:%M:%S', 0) %][% IF !Slash.isAnon(remark.uid); Slash.db.getUser(remark.uid, 'nickname'); END %][% remark.priority || 0 %][% Slash.chopEntity(remark.remark, 120) %][% IF remark.stoid; + thisstory = Slash.db.getStory(remark.stoid); + IF thisstory %]Edit[% + END; + END -%] +
    +[% IF print_div || print_whole %]
    [% END %] +[% IF print_whole %]
    [% END %] + +__seclev__ +10000 +__version__ +$Id: display;remarks;default,v 1.1 2006/07/12 11:41:55 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:55 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:55 +0900 Subject: [Slashdotjp-dev 467] CVS update: slashjp/plugins/ResKey Message-ID: <20060712114155.617DD2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/ResKey/MANIFEST diff -u /dev/null slashjp/plugins/ResKey/MANIFEST:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/MANIFEST Wed Jul 12 20:41:55 2006 @@ -0,0 +1,19 @@ +Makefile.PL +MANIFEST +PLUGIN +ResKey.pm +ResKey/Checks/ACL.pm +ResKey/Checks/AL2/AnonNoPost.pm +ResKey/Checks/AL2/NoPost.pm +ResKey/Checks/AL2/NoPostAnon.pm +ResKey/Checks/AL2.pm +ResKey/Checks/Duration.pm +ResKey/Checks/Post.pm +ResKey/Checks/ProxyScan.pm +ResKey/Checks/User.pm +ResKey/Key.pm +example.plx +mysql_dump.sql +mysql_schema.sql +tasks/reskey_purge.pl +templates/data;reskey;default Index: slashjp/plugins/ResKey/Makefile.PL diff -u /dev/null slashjp/plugins/ResKey/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/Makefile.PL Wed Jul 12 20:41:55 2006 @@ -0,0 +1,10 @@ +use ExtUtils::MakeMaker; + +WriteMakefile( + 'NAME' => 'Slash::ResKey', + 'VERSION_FROM' => 'ResKey.pm', # finds $VERSION +# 'PM' => { +# 'ResKey.pm' => '$(INST_LIBDIR)/ResKey.pm', +# 'ResKey/Checks/User.pm' => '$(INST_LIBDIR)/ResKey/Checks/User.pm', +# }, +); Index: slashjp/plugins/ResKey/PLUGIN diff -u /dev/null slashjp/plugins/ResKey/PLUGIN:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/PLUGIN Wed Jul 12 20:41:55 2006 @@ -0,0 +1,8 @@ +# $Id: PLUGIN,v 1.1 2006/07/12 11:41:55 sugi Exp $ +description="Resource Keys" +name=ResKey +mysql_dump=mysql_dump.sql +mysql_schema=mysql_schema.sql +template=templates/data;reskey;default +template=templates/reskey_tag;misc;default +task=tasks/reskey_purge.pl Index: slashjp/plugins/ResKey/ResKey.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,253 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: ResKey.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey; + +=head1 NAME + +Slash::ResKey - Resource management for Slash + + +=head1 SYNOPSIS + + my $reskey = getObject('Slash::ResKey'); + my $key = $reskey->key('zoo'); + if ($key->create) { ... } + if ($key->touch) { ... } + if ($key->use) { ... } + else { print $key->errstr } + + +=head1 DESCRIPTION + +Slash::ResKey is for managing resources. You get a key object by requesting +a specific sort of resource with the C method, which takes the name +of the resource (an arbitrary string, defined in the database table +C). + +Optionally, C takes a hashref of keys "reskey" and "debug". Debug levels +are 0, 1, and 2, with default 0. If you don't include a reskey, it will +be determined automatically from C. + +See L for more info on what to do with an object returned +by . + +=cut + +use warnings; +use strict; + +use Slash; +use Slash::Constants ':reskey'; +use Slash::ResKey::Key; +use Slash::Utility; + +use base 'Slash::DB::Utility'; +use base 'Slash::DB::MySQL'; + +our($AUTOLOAD); +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +our $DEBUG = 0; + +#======================================================================== +sub new { + my($class, $user) = @_; + my $self = {}; + + my $plugin = getCurrentStatic('plugin'); + return unless $plugin->{'ResKey'}; + + bless($self, $class); + $self->{virtual_user} = $user; + + return $self; +} + +#======================================================================== +sub key { + my($self, $resource, $opts) = @_; + + $opts ||= {}; + $opts->{debug} = $DEBUG unless defined $opts->{debug}; + + return Slash::ResKey::Key->new( + $self->{virtual_user}, + $resource, + $opts->{reskey}, + $opts->{debug}, + $opts + ); +} + +#======================================================================== +# For tasks/reskey_purge.pl +sub purge_old { + my($self) = @_; + + my $count = 0; + + # first, purge all old reskeys + my $timeframe = getCurrentStatic('reskey_timeframe') || 14400; + $count += $self->sqlDelete('reskeys', "create_ts < DATE_SUB(NOW(), INTERVAL $timeframe SECOND)"); + + + # next, purge all reskeys that are used and older than duration_uses + my $uses = $self->sqlSelectAll('rkrid, value', 'reskey_vars', 'name="duration_uses"'); + for (@$uses) { + my($rkrid, $seconds) = @$_; + $count += $self->sqlDelete('reskeys', + "rkrid = $rkrid AND is_alive = 'no' AND " . + "submit_ts IS NOT NULL AND " . + "submit_ts < DATE_SUB(NOW(), INTERVAL $seconds SECOND)" + ); + } + + + # then, delete all used reskeys where duration_uses and + # duration_max-uses are not in use + my $max_uses = $self->sqlSelectAll('rkrid', 'reskey_vars', 'name="duration_max-uses"'); + my %rkids = map { $_->[0] => 1 } (@$uses, @$max_uses); + my $rkid_str = join ', ', keys %rkids; + $count += $self->sqlDelete('reskeys', "rkrid NOT IN ($rkid_str) AND is_alive = 'no'"); + + + # finally, delete orphaned reskey_failures entries + my $rkids = $self->sqlSelectAll('rkf.rkid', + 'reskey_failures AS rkf LEFT JOIN reskeys AS rk ON rk.rkid=rkf.rkid', + 'rk.rkid IS NULL' + ); + + if (@$rkids) { + my $rkid_string = join ',', map { $_->[0] } @$rkids; + $count += $self->sqlDelete('reskey_failures', "rkid IN ($rkid_string)"); + } + + return $count; +} + +1; + +__END__ + + +=head1 SEE ALSO + +Slash(3). + +=head1 VERSION + +$Id: ResKey.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + + +=head1 TODO + +=head2 Check Classes + +The default failure value is DEATH, rather than FAILURE, which is non-fatal: +callers can choose to re-display the form on FAILURE, whereas with DEATH +there's no reason to continue, but one must start over with a new form (if +indeed even that). + +=over 4 + +=item User (DONE) + +Admins can be skipped on these checks with a var. Simple checks for: + +=over 4 + +=item karma + +=item seclev + +=item is_subscriber + +=item is_admin + +=back + + +=item Duration + +We need to implement limit modulation. + +=over 4 + +=item min duration between uses (DONE) + +FAILURE + +=item min duration betwen creation and use (DONE) + +FAILURE + +=item max num of uses per time period (DONE) + +FAILURE + +=item max touches per reskey (NA) + +DEATH + +Not doing now, if ever. But will add if we feel a need. + +=item max simultaneous reskeys (NA) + +FAILURE + +I don't think this is necessary, since we've worked out some atomicity problems. + +If we do: report error, or invalidate old reskeys? Which ones? + +=back + + +=item HumanConf + +Still needs implementation. + + +=item AL2 (DONE) + +=over 4 + +=item NoPost + +This user cannot post. + +=item NoPostAnon + +This user cannot post anonymoously. + +=item AnonNoPost + +This user is anonymous -- or is posting anonymously -- and the anonymous user +cannot post. + +=back + + + +=item Proxy Scan (DONE) + +Simple wrapper around the proxy scan code. + + +=item ACL (DONE) + +If an ACL required, make sure user has it (is_admin bypasses this check (by default)). + +If an ACL prohibits access, make sure user does NOT have it (no bypass). + + +=item POST (NA) + +Probably best handled in .pl as we always have, though we could move it if we +felt a need. + + +=back + Index: slashjp/plugins/ResKey/example.plx diff -u /dev/null slashjp/plugins/ResKey/example.plx:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/example.plx Wed Jul 12 20:41:55 2006 @@ -0,0 +1,52 @@ +use strict; +use Slash::Test shift; + +my($reskey, $rkey, $rkey1, $rkey2, $rkey3); + +my $debug = 0; + +for (1..1) { + $reskey = getObject('Slash::ResKey'); + $rkey = $reskey->key('pollbooth', { + debug => $debug + }); + handle($rkey->createuse, $rkey); + + print Dumper $rkey; + + + $rkey1 = $reskey->key('comments', { + debug => $debug + }); + + handle($rkey1->create, $rkey1); + handle($rkey1->touch, $rkey1); + + $rkey2 = $reskey->key('comments', { + debug => $debug, + reskey => $rkey1->reskey, + }); + + handle($rkey2->touch, $rkey2); + + handle($rkey1->use, $rkey1); + sleep 5; + + $::form->{reskey} = $rkey1->reskey; + $rkey3 = $reskey->key('comments', { + debug => $debug, + }); + handle($rkey3->use, $rkey3) or print Dumper $rkey3; +} + + +sub handle { + my($success, $this_rkey) = @_; + if ($success) { + printf "%s'd %s\n", ucfirst($this_rkey->type), $this_rkey->reskey; + return 1; + } else { + printf "Error on %s: %s\n", $this_rkey->type, $this_rkey->errstr; + print Dumper $this_rkey; + } +} Index: slashjp/plugins/ResKey/flow.txt diff -u /dev/null slashjp/plugins/ResKey/flow.txt:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/flow.txt Wed Jul 12 20:41:55 2006 @@ -0,0 +1,75 @@ +This tersely describes the flow of methods in Slash::ResKey::Key. + +reskey = getObject + +rkey = reskey -> key(RESOURCE_NAME, { reskey => RESKEY, debug => DEBUG }) + get rkey object + + rkey -> create() + rkey -> touch() + rkey -> use() + rkey -> createuse() + main API (generated by _createActionMethod) + + -> fakeUse() + -> getUpdateClauses() + generate SET hashref and WHERE clause for sqlUpdate + + -> check() + -> createCheck() + -> touchCheck() + -> useCheck() + creates a check to execute (generated by _createCheckMethod) + returns method for a given class to execute, looking for + one of the following, in this order, in the given class: + + -> doCheckCreate() + -> doCheckCreateExtra() + -> doCheck() + -> doCheckExtra() + + -> dbCreate() + -> dbTouch() + -> dbUse() + actually perform the create/touch/use in the DB + -> update() + + rkey -> noop + rkey -> success + rkey -> failure + rkey -> death (generated by _createStatusAccessor) + get/set success conditions + + rkey -> errstr + return error string + + rkey -> error (generated by _createAccessor) + returns raw error data + + rkey -> reskey (generated by _createAccessor) + returns reskey string + + rkey -> get + returns the data from the DB row for that reskey + +other methods: + _init + resets stuff in the object + + _save_errors + _restore_errors + for the rare occasion we want to save the errors + before _init blows them away + + getWhereUserClause + set up how to identify the user in the where clause + + getSrcid + get the srcid for the current user + + getResources + get the resources from the DB table + + getChecks + get the checks from the DB table + Index: slashjp/plugins/ResKey/mysql_dump.sql diff -u /dev/null slashjp/plugins/ResKey/mysql_dump.sql:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/mysql_dump.sql Wed Jul 12 20:41:55 2006 @@ -0,0 +1,191 @@ +# +# $Id: mysql_dump.sql,v 1.1 2006/07/12 11:41:55 sugi Exp $ +# + +### NOTE: reserved reskey IDs: +# 1..99 main Slash +# 100..199 Ajax +# 200..999 future Slash use +# 1000+ are open for others to use + +### +# NOTE: AnonNoPost means if you are anonymous, you cannot post, if nopost is set +# for the AC uid. NoPostAnon checks the nopostanon check for the given srcid; +# NoPost checks the nopost check for the given srcid. + +### Possible reskey_vars (default is undef/false unless specified): +# adminbypass - 1/0 - If admin, bypass checks for duration, proxy, ACL, and user +# +# user_is_admin - 1/0 - Requires user to be admin +# user_is_subscriber - 1/0 - Requires user to be subscriber +# user_seclev - \d+ - Minimum seclev to use resource +# user_karma - \d+ - Minimum karma to use resource +# +# acl - \s+ - If this ACL present, can use resource +# acl_no - \s+ - If this ACL present, can't use resource +# +# duration_max-failures - \d+ - how many failures per reskey +# duration_max-uses - \d+ - how many uses per timeframe +# duration_uses - \d+ - min duration (in seconds) between uses +# duration_creation-use - \d+ - min duration between (in seconds) creation and use + + +INSERT INTO vars VALUES ('reskey_srcid_masksize', 24, 'which srcid mask size to use for reskeys'); +INSERT INTO vars VALUES ('reskey_timeframe', 14400, 'Default timeframe base to use for max-uses (in seconds)'); + +INSERT INTO reskey_resources VALUES (1, 'comments'); +INSERT INTO reskey_resources VALUES (2, 'zoo'); +INSERT INTO reskey_resources VALUES (3, 'journal'); +INSERT INTO reskey_resources VALUES (4, 'journal-soap'); +INSERT INTO reskey_resources VALUES (5, 'pollbooth'); +INSERT INTO reskey_resources VALUES (6, 'submit'); +INSERT INTO reskey_resources VALUES (7, 'journal-soap-get'); +INSERT INTO reskey_resources VALUES (8, 'bookmark'); + + + + +##### comments +### checks +# all is for all checks for a given resource, which can be overridden with create/touch/use +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'all', 'Slash::ResKey::Checks::Duration', 601); +INSERT INTO reskey_resource_checks VALUES (NULL, 1, 'use', 'Slash::ResKey::Checks::ProxyScan', 1001); + +# dummy example of how to disable the Slash::ResKey::Checks::User check for "touch" +# (maybe, for example, because the check isn't needed) +#REPLACE INTO reskey_resource_checks VALUES (NULL, 1, 'touch', '', 101); + +### vars +INSERT INTO reskey_vars VALUES (1, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (1, 'acl_no', 'reskey_no_comments', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (1, 'user_seclev', 0, 'Minimum seclev to use resource'); +INSERT INTO reskey_vars VALUES (1, 'duration_max-uses', 30, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (1, 'duration_max-failures', 10, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (1, 'duration_uses', 120, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (1, 'duration_creation-use', 5, 'min duration between (in seconds) creation and use'); + + + + +##### zoo +### checks +INSERT INTO reskey_resource_checks VALUES (NULL, 2, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 2, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 2, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 2, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 2, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 2, 'all', 'Slash::ResKey::Checks::Duration', 601); + +### vars +INSERT INTO reskey_vars VALUES (2, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (2, 'acl_no', 'reskey_no_zoo', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (2, 'user_seclev', 1, 'Minimum seclev to use resource'); +INSERT INTO reskey_vars VALUES (2, 'duration_max-uses', 30, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (2, 'duration_max-failures', 4, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (2, 'duration_uses', 2, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (2, 'duration_creation-use', 2, 'min duration (in seconds) between creation and use'); + + + +##### journal +# note that journal and journal deletion share a reskey. this means if you try +# to delete a few dozen journal entries one at a time, you are screwed. but +# as you can select multiple ones from a list, that should not a problem. +### checks +INSERT INTO reskey_resource_checks VALUES (NULL, 3, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 3, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 3, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 3, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 3, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 3, 'all', 'Slash::ResKey::Checks::Duration', 601); + +### vars +INSERT INTO reskey_vars VALUES (3, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (3, 'acl_no', 'reskey_no_journal', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (3, 'user_seclev', 1, 'Minimum seclev to use resource'); +INSERT INTO reskey_vars VALUES (3, 'duration_max-uses', 30, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (3, 'duration_max-failures', 10, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (3, 'duration_uses', 30, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (3, 'duration_creation-use', 2, 'min duration (in seconds) between creation and use'); + + +##### journal-soap +### checks +INSERT INTO reskey_resource_checks VALUES (NULL, 4, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 4, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 4, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 4, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 4, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 4, 'all', 'Slash::ResKey::Checks::Duration', 601); + +### vars +INSERT INTO reskey_vars VALUES (4, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +#INSERT INTO reskey_vars VALUES (4, 'acl', 'reskey_journal-soap', 'If this ACL present, can use resource'); +INSERT INTO reskey_vars VALUES (4, 'acl_no', 'reskey_no_journal', 'If this ACL present, can\'t use resource'); +#INSERT INTO reskey_vars VALUES (4, 'user_is_subscriber', 1, 'Require user to be subscriber'); +INSERT INTO reskey_vars VALUES (4, 'user_seclev', 1, 'Minimum seclev to use resource'); +INSERT INTO reskey_vars VALUES (4, 'duration_max-uses', 30, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (4, 'duration_max-failures', 10, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (4, 'duration_uses', 30, 'min duration (in seconds) between uses'); + + +##### journal-soap-get +### checks +INSERT INTO reskey_resource_checks VALUES (NULL, 7, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 7, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 7, 'all', 'Slash::ResKey::Checks::Duration', 601); + +### vars +INSERT INTO reskey_vars VALUES (7, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +#INSERT INTO reskey_vars VALUES (7, 'acl', 'reskey_journal-soap', 'If this ACL present, can use resource'); +INSERT INTO reskey_vars VALUES (7, 'acl_no', 'reskey_no_journal', 'If this ACL present, can\'t use resource'); +#INSERT INTO reskey_vars VALUES (7, 'user_is_subscriber', 1, 'Require user to be subscriber'); +INSERT INTO reskey_vars VALUES (7, 'duration_max-failures', 1, 'how many failures per reskey'); + + + +##### pollbooth +### checks +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'use', 'Slash::ResKey::Checks::Post', 151); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::PollBooth::ResKey', 251); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 5, 'all', 'Slash::ResKey::Checks::Duration', 601); + +### vars +INSERT INTO reskey_vars VALUES (5, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (5, 'acl_no', 'reskey_no_pollbooth', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (5, 'duration_max-uses', 10, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (5, 'duration_max-failures', 3, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (5, 'duration_uses', 10, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (5, 'duration_creation-use', 2, 'min duration (in seconds) between creation and use'); + + + +##### submit +### checks +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::User', 101); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'use', 'Slash::ResKey::Checks::Post', 151); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::ACL', 201); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::AL2::AnonNoPost', 301); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::AL2::NoPostAnon', 401); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::AL2::NoPost', 501); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::AL2::NoSubmit', 551); +INSERT INTO reskey_resource_checks VALUES (NULL, 6, 'all', 'Slash::ResKey::Checks::Duration', 601); + +### vars +INSERT INTO reskey_vars VALUES (6, 'adminbypass', 1, 'If admin, bypass checks for duration, proxy, and user'); +INSERT INTO reskey_vars VALUES (6, 'acl_no', 'reskey_no_submit', 'If this ACL present, can\'t use resource'); +INSERT INTO reskey_vars VALUES (6, 'duration_max-uses', 20, 'how many uses per timeframe'); +INSERT INTO reskey_vars VALUES (6, 'duration_max-failures', 10, 'how many failures per reskey'); +INSERT INTO reskey_vars VALUES (6, 'duration_uses', 300, 'min duration (in seconds) between uses'); +INSERT INTO reskey_vars VALUES (6, 'duration_creation-use', 20, 'min duration (in seconds) between creation and use'); + Index: slashjp/plugins/ResKey/mysql_schema.sql diff -u /dev/null slashjp/plugins/ResKey/mysql_schema.sql:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/mysql_schema.sql Wed Jul 12 20:41:55 2006 @@ -0,0 +1,65 @@ +# +# $Id: mysql_schema.sql,v 1.1 2006/07/12 11:41:55 sugi Exp $ +# + +DROP TABLE IF EXISTS reskeys; +CREATE TABLE reskeys ( + rkid INT NOT NULL AUTO_INCREMENT, + reskey CHAR(20) DEFAULT '' NOT NULL, # unique resource key string + rkrid SMALLINT UNSIGNED NOT NULL, # points to reskey_resources.rkrid + + uid MEDIUMINT UNSIGNED DEFAULT 0 NOT NULL, + srcid_ip BIGINT UNSIGNED DEFAULT 0 NOT NULL, + + failures TINYINT DEFAULT 0 NOT NULL, # number of failures of this key + touches TINYINT DEFAULT 0 NOT NULL, # number of touches (not including failures, or successful uses) of this key + is_alive ENUM('yes', 'no') DEFAULT 'yes' NOT NULL, + + create_ts DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL, # on create + last_ts DATETIME DEFAULT '0000-00-00 00:00:00' NOT NULL, # last use + submit_ts DATETIME DEFAULT NULL, # on success + + PRIMARY KEY (rkid), + UNIQUE reskey (reskey), + KEY rkrid (rkrid), + KEY uid (uid), + KEY srcid_ip (srcid_ip), + KEY create_ts (create_ts), + KEY last_ts (last_ts), + KEY submit_ts (submit_ts) +) TYPE=InnoDB; + +DROP TABLE IF EXISTS reskey_failures; +CREATE TABLE reskey_failures ( + rkid INT NOT NULL, + failure VARCHAR(255) DEFAULT '' NOT NULL, + PRIMARY KEY (rkid) +) TYPE=InnoDB; + +DROP TABLE IF EXISTS reskey_resources; +CREATE TABLE reskey_resources ( + rkrid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, + name VARCHAR(64), + PRIMARY KEY (rkrid) +) TYPE=InnoDB; + +DROP TABLE IF EXISTS reskey_resource_checks; +CREATE TABLE reskey_resource_checks ( + rkrcid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, + rkrid SMALLINT UNSIGNED NOT NULL, + type ENUM('create', 'touch', 'use', 'all') NOT NULL, + class VARCHAR(255), + ordernum SMALLINT UNSIGNED DEFAULT 0, + PRIMARY KEY (rkrcid), + UNIQUE rkrid_name (rkrid, type, class) +) TYPE=InnoDB; + +DROP TABLE IF EXISTS reskey_vars; +CREATE TABLE reskey_vars ( + rkrid SMALLINT UNSIGNED NOT NULL, + name VARCHAR(48) DEFAULT '' NOT NULL, + value TEXT, + description VARCHAR(255), + UNIQUE name_rkrid (name, rkrid) +) TYPE=InnoDB; + From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:55 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:55 +0900 Subject: [Slashdotjp-dev 468] CVS update: slashjp/plugins/ResKey/ResKey/Checks Message-ID: <20060712114155.C9E6A2AC00E@users.sourceforge.jp> Index: slashjp/plugins/ResKey/ResKey/Checks/ACL.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/ACL.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/ACL.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,44 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: ACL.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::ACL; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + + my $user = getCurrentUser(); + my $check_vars = $self->getCheckVars; + + my $acl = $check_vars->{acl}; + my $acl_no = $check_vars->{acl_no}; + + # is_admin is an exception to lack of ACL if adminbypass set + my $acl_nobypass_admin = (!$user->{is_admin} || ( + $user->{is_admin} && !$check_vars->{adminbypass} + )); + + if ($acl && !$user->{acl}{$acl} && $acl_nobypass_admin) { + return(RESKEY_DEATH, [ 'has no acl', { acl => $acl } ]); + } + + # is_admin does not bypass acl_no + if ($acl_no && $user->{acl}{$acl_no}) { + return(RESKEY_DEATH, [ 'has acl_no', { acl => $acl_no } ]); + } + + return RESKEY_SUCCESS; +} + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/AL2.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/AL2.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/AL2.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,35 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: AL2.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::AL2; + +use warnings; +use strict; + +use Exporter; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; +our @EXPORT = qw(AL2Check); + +# simple AL2 check that others can inherit; returns death if check returns true +sub AL2Check { + my($self, $check, $srcids) = @_; + + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + + $srcids ||= $user->{srcids}; + + if ($slashdb->checkAL2($srcids, $check)) { + return(RESKEY_DEATH, ["$check al2 failure"]); + } + + return RESKEY_SUCCESS; +} + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/Duration.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/Duration.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/Duration.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,189 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: Duration.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::Duration; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + + +sub doCheckCreate { + my($self) = @_; + + my $user = getCurrentUser(); + my $check_vars = $self->getCheckVars; + + if ($check_vars->{adminbypass} && $user->{is_admin}) { + return RESKEY_SUCCESS; + } + + my @return = maxUsesPerTimeframe($self); + return @return || RESKEY_SUCCESS; +} + +sub doCheckTouch { + my($self) = @_; + + my $user = getCurrentUser(); + my $check_vars = $self->getCheckVars; + + if ($check_vars->{adminbypass} && $user->{is_admin}) { + return RESKEY_SUCCESS; + } + + my $reskey_obj = $self->get; + + my @return = maxUsesPerTimeframe($self, $reskey_obj); + return @return if @return; + + @return = maxFailures($self, $reskey_obj); + return @return if @return; + + return RESKEY_SUCCESS; +} + +sub doCheckUse { + my($self) = @_; + + my $user = getCurrentUser(); + my $check_vars = $self->getCheckVars; + + if ($check_vars->{adminbypass} && $user->{is_admin}) { + return RESKEY_SUCCESS; + } + + my $reskey_obj = $self->get; + + my @return = maxUsesPerTimeframe($self, $reskey_obj); + return @return if @return; + + @return = maxFailures($self, $reskey_obj); + return @return if @return; + + # we only check these on use, not create or touch, because the limits + # are so short that there's no point in checking them until use, so + # as not to increase the chance of giving users a rather spurious error + + @return = minDurationBetweenUses($self, $reskey_obj); + return @return if @return; + + if ($self->origtype ne 'createuse') { + @return = minDurationBetweenCreateAndUse($self, $reskey_obj); + return @return if @return; + } + + return RESKEY_SUCCESS; +} + +sub maxFailures { + my($self, $reskey_obj) = @_; + $reskey_obj ||= {}; + + my $slashdb = getCurrentDB(); + my $check_vars = $self->getCheckVars; + + my $max_failures = $check_vars->{'duration_max-failures'}; + if ($max_failures && $reskey_obj->{rkid}) { + my $where = "rkid=$reskey_obj->{rkid} AND failures > $max_failures"; + my $rows = $slashdb->sqlCount('reskeys', $where); + if ($rows) { + return(RESKEY_DEATH, ['too many failures', { + max_failures => $max_failures, + uses => $rows + }]); + } + } + + return; +} + +sub maxUsesPerTimeframe { + my($self, $reskey_obj) = @_; + $reskey_obj ||= {}; + + my $constants = getCurrentStatic(); + my $slashdb = getCurrentDB(); + my $check_vars = $self->getCheckVars; + + my $max_uses = $check_vars->{'duration_max-uses'}; + my $limit = $constants->{reskey_timeframe}; + if ($max_uses && $limit) { + my $where = $self->getWhereUserClause; + $where .= ' AND rkrid=' . $self->rkrid; + $where .= ' AND is_alive="no" AND '; + $where .= "rkid != '$reskey_obj->{rkid}' AND " if $reskey_obj->{rkid}; + $where .= "submit_ts > DATE_SUB(NOW(), INTERVAL $limit SECOND)"; + + my $rows = $slashdb->sqlCount('reskeys', $where); + if ($rows >= $max_uses) { + return(RESKEY_DEATH, ['too many uses', { + timeframe => $limit, + max_uses => $max_uses, + uses => $rows + }]); + } + } + + return; +} + +sub minDurationBetweenUses { + my($self, $reskey_obj) = @_; + + my $slashdb = getCurrentDB(); + my $check_vars = $self->getCheckVars; + + my $limit = $check_vars->{duration_uses}; + if ($limit) { + my $where = $self->getWhereUserClause; + $where .= ' AND rkrid=' . $self->rkrid; + $where .= ' AND is_alive="no" AND '; + $where .= "rkid != '$reskey_obj->{rkid}' AND " if $reskey_obj->{rkid}; + $where .= "submit_ts > DATE_SUB(NOW(), INTERVAL $limit SECOND)"; + + my $rows = $slashdb->sqlCount('reskeys', $where); + if ($rows) { + return(RESKEY_FAILURE, ['use duration too short', + { duration => $limit } + ]); + } + } + + return; +} + +sub minDurationBetweenCreateAndUse { + my($self, $reskey_obj) = @_; + + my $slashdb = getCurrentDB(); + my $check_vars = $self->getCheckVars; + + my $limit = $check_vars->{'duration_creation-use'}; + if ($limit && $reskey_obj->{rkid}) { + my $where = "rkid=$reskey_obj->{rkid}"; + $where .= ' AND rkrid=' . $self->rkrid; + $where .= ' AND is_alive="no" AND '; + $where .= "create_ts > DATE_SUB(NOW(), INTERVAL $limit SECOND)"; + + my $rows = $slashdb->sqlCount('reskeys', $where); + if ($rows) { + return(RESKEY_FAILURE, ['creation-use duration too short', + { duration => $limit } + ]); + } + } + + return; +} + + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/Post.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/Post.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/Post.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,33 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: Post.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::Post; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + + return RESKEY_NOOP unless $ENV{GATEWAY_INTERFACE}; + + my $user = getCurrentUser(); + + if (!$user->{state}{post}) { + return(RESKEY_FAILURE, ['post method required']); + } + + return RESKEY_SUCCESS; +} + + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/ProxyScan.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/ProxyScan.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/ProxyScan.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,47 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: ProxyScan.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::ProxyScan; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + + if (!$ENV{GATEWAY_INTERFACE}) { + return RESKEY_SUCCESS; + } + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $user = getCurrentUser(); + my $check_vars = $self->getCheckVars; + + if ($check_vars->{adminbypass} && $user->{is_admin}) { + return RESKEY_SUCCESS; + } + + if (!$reader->getAL2($user->{srcids}, 'trusted')) { + my $is_proxy = $reader->checkForOpenProxy($user->{srcids}{ip}); + if ($is_proxy) { + return(RESKEY_DEATH, ['open proxy', { + unencoded_ip => $ENV{REMOTE_ADDR}, + port => $is_proxy, + }]); + } + } + + return RESKEY_SUCCESS; +} + + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/User.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/User.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/User.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,38 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: User.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::User; + +use warnings; +use strict; + +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + + my $user = getCurrentUser(); + my $check_vars = $self->getCheckVars; + + if ($check_vars->{adminbypass} && $user->{is_admin}) { + return RESKEY_SUCCESS; + } + + for my $check (qw(is_admin seclev is_subscriber karma tags_canread_stories tags_canwrite_stories)) { + my $value = $check_vars->{"user_${check}"}; + if (defined $value && length $value && (!$user->{$check} || $user->{$check} < $value)) { + return(RESKEY_DEATH, ["$check too low", { needed => $value }]); + } + } + + return RESKEY_SUCCESS; +} + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:55 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:55 +0900 Subject: [Slashdotjp-dev 469] CVS update: slashjp/plugins/ResKey/ResKey/Checks/AL2 Message-ID: <20060712114155.EE52F2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/ResKey/ResKey/Checks/AL2/AnonNoPost.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/AL2/AnonNoPost.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/AL2/AnonNoPost.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,38 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: AnonNoPost.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::AL2::AnonNoPost; + +use warnings; +use strict; + +use Slash::ResKey::Checks::AL2; +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + + my $user = getCurrentUser(); + my $form = getCurrentForm(); + + # this check assumes only one AC uid, and doesn't accept any + # other UIDs to be provided + + if ($user->{is_anon} || $form->{postanon}) { + return AL2Check( + $self, 'nopost', + { uid => getCurrentAnonymousCoward('uid') }, + ); + } else { + return RESKEY_NOOP; + } +} + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/AL2/NoPost.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/AL2/NoPost.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/AL2/NoPost.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,24 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: NoPost.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::AL2::NoPost; + +use warnings; +use strict; + +use Slash::ResKey::Checks::AL2; +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + return AL2Check($self, 'nopost'); +} + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/AL2/NoPostAnon.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/AL2/NoPostAnon.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/AL2/NoPostAnon.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,24 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: NoPostAnon.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::AL2::NoPostAnon; + +use warnings; +use strict; + +use Slash::ResKey::Checks::AL2; +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + return AL2Check($self, 'nopostanon'); +} + +1; Index: slashjp/plugins/ResKey/ResKey/Checks/AL2/NoSubmit.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Checks/AL2/NoSubmit.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Checks/AL2/NoSubmit.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,24 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: NoSubmit.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Checks::AL2::NoSubmit; + +use warnings; +use strict; + +use Slash::ResKey::Checks::AL2; +use Slash::Utility; +use Slash::Constants ':reskey'; + +use base 'Slash::ResKey::Key'; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub doCheck { + my($self) = @_; + return AL2Check($self, 'nosubmit'); +} + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:55 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:55 +0900 Subject: [Slashdotjp-dev 470] CVS update: slashjp/plugins/ResKey/ResKey Message-ID: <20060712114155.961582AC0F4@users.sourceforge.jp> Index: slashjp/plugins/ResKey/ResKey/Key.pm diff -u /dev/null slashjp/plugins/ResKey/ResKey/Key.pm:1.1 --- /dev/null Wed Jul 12 20:41:55 2006 +++ slashjp/plugins/ResKey/ResKey/Key.pm Wed Jul 12 20:41:55 2006 @@ -0,0 +1,884 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: Key.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +package Slash::ResKey::Key; + +=head1 NAME + +Slash::ResKey::Key - Resource management for Slash + + +=head1 SYNOPSIS + + my $reskey = getObject('Slash::ResKey'); + my $key = $reskey->key('zoo'); + if ($key->create) { ... } + if ($key->touch) { ... } + if ($key->use) { ... } + else { print $key->errstr } + + +=head1 DESCRIPTION + +After getting an object from C (see L), you may perform +three primary operations on the object. + +Each of these performs checks as defined for that object's resource, as listed +in the C table. The rows in that table define the +classes, and the order in which those classes are to be checked. Each class +defines the methods for executing the checks. + +=over 4 + +=item create + +To create a reskey to be used, call C. After running the checks, +a new reskey is inserted in the C table. + +=item touch + +When a reskey is tested, but not used up -- for example, in previewing, but +not yet submitting, a comment -- call C. This performs the checks, +and marks the reskey as having been touched. + +=item use + +Call C to finally use the reskey to unlock the resource, so it can +be used. After the checks are run, the reskey is invalidated and may not be +used again. + +(There is also a C method, which first creates the reskey if +necesssary [it won't create one if it is already supplied], and then +immediately attempts to use it, for forms that don't need a preexisting +reskey already in the form from a previous C. Treat it as +a C.) + +=back + + +Each of the above methods returns true for success, and false for failure. +For failure, you can check C to get the error string to present to +the user. + +There are two failure conditions, C and C. By default, most +are C, which means the reskey failure is fatal: you cannot try again. +However, some checks -- such as the one to make sure there's been enough +time between submission of comments -- are C. If you wish to +continue after a C or C returns false, you may do so if C +returns true: + + unless ($rkey->use) { + if ($rkey->failure) { + # try again + } else { + # you're hosed + } + } + +You may also check the two success conditions, C and C. + +Assuming you're calling C and later C, rather than just +C, you'll want to send the created reskey's value to the +user so that it can be submitted back later. It is returned by the +C method. Either pass the entire key object to the form, or +just the reskey value itself: + + slashDisplay('myForm', { rkey => $rkey }); + + + +Or: + + slashDisplay('myForm', { reskey_value => $rkey->reskey }); + + + +But the easiest way is to just call the F template, which does the +right thing for you (you don't even need to pass anything to slashDisplay; +just make sure the reskey work is done in your code before calling this +in your template): + + [% PROCESS reskey_tag %] + + +There's also a C method which returns the row from the C +database for that reskey. + +=cut + +use warnings; +use strict; + +use Time::HiRes; +use Slash; +use Slash::Constants ':reskey'; +use Slash::Utility; + +our($AUTOLOAD); +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +#======================================================================== +sub new { + my($class, $user, $resname, $reskey, $debug, $opts) = @_; + my $rkrid; + + my $plugin = getCurrentStatic('plugin'); + return 0 unless $plugin->{'ResKey'}; + + # we get the reskey automatically if it exists, can also + # override by passing + my $self = bless { _opts => $opts }, $class; + + $self->debug($debug); + + if ($resname =~ /[a-zA-Z]/) { + my $resources = $self->getResources; + $rkrid = $resources->{name}{$resname}; + } elsif ($resname =~ /^\d+$/) { + my $resources = $self->getResources; + $rkrid = $resname; + $resname = $resources->{id}{$rkrid}; + } + + return 0 unless $resname && $rkrid; + + $self->resname($resname); + $self->rkrid($rkrid); + + + # from filter_param + if ($reskey) { + $reskey =~ s|[^a-zA-Z0-9_]+||g; + } elsif (!defined $reskey) { + $reskey = $opts->{nostate} ? '' : getCurrentForm('reskey'); + } + + # reskey() to set the value is called only here and from dbCreate + # this is the only place $form->{reskey} is looked at + $self->reskey($reskey); + + $self->_init; + + return $self; +} + +#======================================================================== +# print out what method we're in +sub _flow { + my($self, $name) = @_; + # accessor calls _flow ... so don't call debug() + return unless defined $self->{_debug} && $self->{_debug} > 1; + + my @caller1 = caller(1); + my $name1 = $caller1[3]; + + if ($name) { + $name1 =~ s/::[^:]+$/::$name/; + } + + printf STDERR "ResKey flow: calling %-40s\n", $name1; +} + +#======================================================================== +# call to reset values before doing anything requiring a return value +sub _init { + my($self) = @_; + $self->_flow; + $self->{_code} = 0; + delete $self->{_errstr}; + delete $self->{_error}; + delete $self->{_reskey_obj}; + return 1; +} + +#======================================================================== +# sometimes we may wish to save/restore errors and codes +sub _save_errors { + my($self) = @_; + $self->_flow; + $self->{_save_errors} = { + _code => $self->{_code}, + _errstr => $self->{_errstr}, + _error => $self->{_error}, + }; + return 1; +} + +sub _restore_errors { + my($self) = @_; + $self->_flow; + $self->{_code} = $self->{_save_errors}{_code}; + $self->{_errstr} = $self->{_save_errors}{_errstr}; + $self->{_error} = $self->{_save_errors}{_error}; + delete $self->{_save_errors}; + return 1; +} + +#======================================================================== +sub can { + my($self, $meth) = @_; + return unless @_ == 2; + my $can = UNIVERSAL::can($self, $meth); + unless ($can) { + $AUTOLOAD = ref($self) . '::' . $meth; + $can = AUTOLOAD('AUTOLOAD::can', $self); + } + return $can; +} + +#======================================================================== +# a lot of methods around these parts just copy each other, so +# we use AUTOLOAD to make things a bit simpler to modify +sub AUTOLOAD { + my $can = $_[0] eq 'AUTOLOAD::can' ? shift : 0; + (my $name = $AUTOLOAD) =~ s/^.*://; + my $sub; + + # when called as a package class, package + # may not be in the name ... + my $full = $AUTOLOAD; + $full = "$_[0]$full" if $full =~ /^::\w+$/; + + if ($name =~ /^(?:noop|success|failure|death)$/) { + $sub = _createStatusAccessor($name, \@_); + + } elsif ($name =~ /^(?:error|reskey|debug|rkrid|resname|origtype|type|code|opts)$/) { + $sub = _createAccessor($name, \@_); + + } elsif ($name =~ /^(?:create|touch|use|createuse)$/) { + $sub = _createActionMethod($name, \@_); + + } elsif ($name =~ /^(?:checkCreate|checkTouch|checkUse)$/) { + $sub = _createCheckMethod($name, \@_); + } + + # we create methods as needed, and only once + if ($sub) { + no strict 'refs'; + +#print STDERR "Creating new method $full\n"; + + *{$full} = $sub; + return $sub if $can; + goto &$sub; + + } elsif (!$can) { + errorLog("no method $name") unless + $name =~ /^(?:DESTROY)$/; + return; + } +} + +#======================================================================== +# we have various simple accessors +sub _createAccessor { + my($name) = @_; + my $newname = "_$name"; + return sub { + my($self, $value) = @_; + $self->_flow($name); + if (defined $value) { + if ($name eq 'reskey' && !$self->opts->{nostate}) { + # Setting reskey() is special, it gets + # stored in the $user object as well. + my $user = getCurrentUser(); + $user->{state}{reskey} = $value; + } + $self->{$newname} = $value; + } + return $self->{$newname}; + }; +} + +#======================================================================== +# each key can have one of three status results: success, failure, death +# checks can also return noop +sub _createStatusAccessor { + my($name) = @_; + my $constant = $Slash::Constants::CONSTANTS{reskey}{"RESKEY_\U$name"}; + return sub { + my($self, $set) = @_; + $self->_flow($name); + if ($set) { + $self->code($constant); + return 1; + } + return 0 unless defined $self->code; + return $self->code == $constant ? 1 : 0; + }; +} + +#======================================================================== +# for the main methods: create, touch, use (and createuse) +# they call private methods named same thing, but with underscore +sub _createActionMethod { + my($name) = @_; + return sub { + my($self) = @_; + $self->_flow($name); + $self->type($name); + $self->origtype($name); + + # first create a reskey, skipping the checks. + # your job to make sure any check needed for + # create is done for use, too. + if ($self->type eq 'createuse') { + $self->type('use'); + unless ($self->reskey) { + $self->dbCreate; + } + } + + if ($self->type eq 'use') { + return 0 unless $self->fakeUse; + } + + my $ok = $self->check; +# fake an error +# if ($self->type eq 'use') { +# $self->death(1); +# $self->error(['dummy error']); +# } + + # don't bother if type is create, and checks failed ... + # we only continue on for touch/use to update the DB + # to note we've been here, to clean up, etc. + if ($self->type ne 'create' || $ok) { + my $method_name = 'db' . ucfirst($self->type); + $ok = $self->$method_name(); + } + + return $ok; + }; +} + +#======================================================================== +# this creates a method for when createCheck/touchCheck/useCheck +# is called. it looks in the class for (in order): doCheckCreate, +# doCheckCreateExtra, doCheck, doCheckExtra. +# +# "Extra" is for future expansion, allowing a check method to return +# more than just the two main arguments: code and error hashref. Those +# methods are used as-is, while the non-Extra versions are wrapped in +# another method. +# +# First, the specific method for the check type is tried (doCheckCreate), +# then the Extra version of it; then the generic check method +# for all check types is tried (doCheck), then finally the Extra version +# of it. +# +# If none of those is found, then a method returning NOOP is returned. + +sub _createCheckMethod { + my($name, $args) = @_; + my($class, $self) = @$args; + + my $base = 'doCheck'; + my $extra = 'Extra'; + my $base_name = "do\u$name"; + + # doCheckCreate + my $meth = $class->can($base_name); + print STDERR " Using $base_name\n" if $meth && $self->debug; + + # doCheckCreateExtra + if (!$meth) { + $meth = $class->can($base_name.$extra); + if ($meth) { + print STDERR " Using $base_name$extra\n" if $self->debug; + return $meth; + } + } + + # doCheck + if (!$meth) { + $meth = $class->can($base); + print STDERR " Using $base\n" if $meth && $self->debug; + } + + # doCheckExtra + if (!$meth) { + $meth = $class->can($base.$extra); + if ($meth) { + print STDERR " Using $base$extra\n" if $self->debug; + return $meth; + } + } + + if (!$meth) { + print STDERR " Using NOOP\n" if $self->debug; + return sub { return { code => RESKEY_NOOP } } + } + + return sub { + my($pkg, $self) = @_; + $self->_flow($name); + my($code, $error) = $meth->($self); + return { + code => $code, + error => $error, + }; + }; +} + +#======================================================================== +sub dbCreate { + my($self) = @_; + $self->_flow; + $self->_init; + + my $constants = getCurrentStatic(); + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + + my $ok = 0; + my $srcid = $self->getSrcid; + + # XXX We really should pull this repeat-insert-getAnonId + # loop into a utility function in Environment.pm. It's + # repeated in createFormkey (and would be in + # createDaypasskey except I don't think it's even worth + # bothering). When we do pull it out, remember to lose + # the 'use Time::HiRes' :) + my $reskey = ''; + my $try_num = 1; + my $num_tries = 10; + while ($try_num < $num_tries) { + $reskey = getAnonId(1, 20); + my $rows = $slashdb->sqlInsert('reskeys', { + reskey => $reskey, + rkrid => $self->rkrid, + uid => $user->{uid}, + -srcid_ip => $srcid, + -create_ts => 'NOW()', + }); + + if ($rows > 0) { + $self->reskey($reskey); + $ok = 1; + last; + } + + # The INSERT failed because $reskey is already being + # used. Presumably this would be due to a collision + # in the randomly-generated string, which indicates + # there's a problem with the RNG (since with a true + # RNG this would happen once every kajillion years). + # Keep retrying, but we're going to log this once + # we're done. + ++$try_num; + # Pause before trying again; in the event of a + # problem with the RNG, lots of places in the code + # are probably trying this all at once and this may + # make the site fail more gracefully. + Time::HiRes::sleep(rand($try_num)); + } + if ($try_num > 1) { + errorLog("Slash::ResKey::Key->create INSERT failed $try_num times: uid=$user->{uid} rkrid=$self->{rkrid} reskey=$reskey"); + } + + if ($ok) { + $self->success(1); + } else { + $self->death(1); + $self->error(['create failed']); + } + + return $self->success; +} + +#======================================================================== +# dbTouch and dbUse are same, except dbUse also deals with submit_ts and is_alive +*dbTouch = \&dbUse; +sub dbUse { + my($self) = @_; + $self->_flow; + my($failed, $failure_string); + if (!$self->success) { + $failed = $self->error; + $failure_string = ref($failed) ? $failed->[0] : $failed; + $self->_save_errors; + } + $self->_init; + + my(%update, $where, $no_is_alive_check); + %update = ( + -touches => 'touches+1', + -last_ts => 'NOW()', + ); + + if ($failed) { + $update{-failures} = 'failures+1'; + } + + if ($self->type eq 'use') { + # use(), or to be precise fakeUse() called by the + # use() method created by _createActionMethod(), + # already set is_alive to no, assuming success. + $no_is_alive_check = 1; + if ($failed) { + # re-set these, as they were set by use(), + # assuming success + $update{-submit_ts} = 'NULL'; + $update{is_alive} = 'yes'; + } else { + # update the ts again, just to be clean + $update{-submit_ts} = 'NOW()'; + } + } + + $self->getUpdateClauses(\%update, \$where, + $no_is_alive_check) or return 0; + + my $slashdb = getCurrentDB(); + my $rows = $slashdb->sqlUpdate('reskeys', \%update, $where); + + if ($failed) { + $self->_restore_errors; + } elsif ($rows == 1) { + $self->success(1); + } else { + $self->death(1); + # we may want this error to be more finely detailed, + # which may require additional SELECTs to find out + # exactly what the problem is, or we could just + # say the reskey is not valid + $failure_string = 'touch-use failed'; + $self->error([$failure_string]); + } + + if ($failure_string) { + my $reskey_obj = $self->get; + if ($reskey_obj) { + my $rkid = $reskey_obj->{rkid}; + if ($rkid) { + $slashdb->sqlReplace('reskey_failures', { + rkid => $rkid, + failure => $failure_string + }); + } + } + } + + return $self->success; +} + +#======================================================================== +# some of these could be separate checks, but they happen for every reskey, +# and it is best for atomicity and performance to do them when we actually +# update the reskey +sub getUpdateClauses { + my($self, $update, $where, $no_is_alive_check) = @_; + $self->_flow; + + my $constants = getCurrentStatic(); + my $slashdb = getCurrentDB(); + my $user = getCurrentUser(); + + my $reskey_obj = $self->get; + return 0 unless $reskey_obj; + + my $srcid = $self->getSrcid; + + my $rkrid = $self->rkrid; + + my $where_base = "rkid=$reskey_obj->{rkid} AND rkrid=$rkrid"; + $where_base .= " AND is_alive='yes'" unless $no_is_alive_check; + if ($$where) { + $$where .= " AND $where_base"; + } else { + $$where = $where_base; + } + + # If user has logged in since getting reskey, we update the uid, + # but still check this time by srcid. - Pudge + # And if the user has logged OUT since getting the reskey, + # getWhereUserClause will just treat them as anon, as, + # presumably, the caller script will also. + if (isAnon($reskey_obj->{uid}) && !$user->{is_anon}) { + $update->{uid} = $user->{uid}; + $$where .= ' AND srcid_ip=' . $self->getSrcid; + } else { # use uid or srcid as appropriate + $$where .= ' AND ' . $self->getWhereUserClause; + } + + return 1; +} + +#======================================================================== +sub getWhereUserClause { + my($self, $options) = @_; + $self->_flow; + + my $user = getCurrentUser(); + my $where; + + # anonymous user without cookie, check host, not srcid + if ($user->{is_anon} || $options->{force_srcid}) { + $where = 'srcid_ip=' . $self->getSrcid; + } else { + $where = "uid=$user->{uid}"; + } + + return $where; +} + +#======================================================================== +# if we are going to use this reskey, set it as used +# up front, then un-use it if use fails, for the sake +# of faking atomicity +sub fakeUse { + my($self) = @_; + $self->_flow; + $self->_init; + + my $where; + my %update = ( + -submit_ts => 'NOW()', + is_alive => 'no', + ); + + $self->getUpdateClauses(\%update, \$where) or return 0; + + my $slashdb = getCurrentDB(); + my $rows = $slashdb->sqlUpdate('reskeys', \%update, $where); + + if ($rows == 1) { + $self->success(1); + } else { + # we don't know what happened here ... bail + $self->death(1); + $self->error(['touch-use failed']); + } + + return $self->success; +} + +#======================================================================== +sub check { # basically same for checkUse, maybe share same code + my($self) = @_; + $self->_flow; + $self->_init; + + # checkUse + my $meth = 'check' . ucfirst($self->type); + + # getChecks will return 0 for failure, and an empty hashref + # if we simply have no checks to perform + my $checks = $self->getChecks; + if (!$checks) { + $self->death(1); + return 0; + } + + for my $class (@$checks) { + # $class implements each of + # create, touch, and use methods + loadClass($class); # loadClass in Environment.pm + errorLog("Can't load $class: $@"), next if $@; + + # any data the $check needs will be in $self + print STDERR "Checking $class : $meth\n" if $self->debug; + + #Slash::ResKey::Checks::User->checkUse + my $result = $class->$meth($self); + + # higher number takes precedence + # (we start with success (code == 0), so + # noop (code == -1) is skipped) + if ($result->{code} > $self->code) { + $self->code($result->{code}); + + # otherwise not an error + if ($self->code > RESKEY_SUCCESS) { + $self->error($result->{error}); + } + + # no need to keep processing + last if $self->code >= RESKEY_DEATH; + } + printf STDERR (" Status: %d : %d\n", + $result->{code}, $self->code) if $self->debug; + } + + return $self->success; +} + +#======================================================================== +sub errstr { + my($self) = @_; + $self->_flow; + return $self->{_errstr} if $self->{_errstr}; + + my $errstr; + my $error = $self->error; + + if ($error) { + if (ref($error) eq 'ARRAY') { + $error->[2] ||= 'reskey'; + $error->[1]{rkey} = $self; + $errstr = getData(@$error); + } else { + $errstr = $error; + } + } + + return $self->{_errstr} = $errstr; +} + +#======================================================================== +sub get { + my($self, $refresh) = @_; + $self->_flow; + return $self->{_reskey_obj} if !$refresh && $self->{_reskey_obj}; + + my $slashdb = getCurrentDB(); + my $reskey_obj; + + if ($self->reskey) { + my $reskey_q = $slashdb->sqlQuote($self->reskey); + $reskey_obj = $slashdb->sqlSelectHashref('*', 'reskeys', "reskey=$reskey_q"); + } + + if (!$reskey_obj) { + $self->death(1); + $self->error(['reskey not found']); + } + + return $self->{_reskey_obj} = $reskey_obj; +} + +#======================================================================== +sub getSrcid { + my($self) = @_; + $self->_flow; + + return $self->{_srcid_ip} if $self->{_srcid_ip}; + + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + return $self->{_srcid_ip} = get_srcid_sql_in( + $user->{srcids}{ $constants->{reskey_srcid_masksize} || 24 } + ); +} + +#======================================================================== +sub getResources { + my($self) = @_; + $self->_flow; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $name = 'reskey_resources'; + my $cache = "_${name}_cache"; + my $cache_time = "_${name}_cache_time"; + my $expire_time = getCurrentStatic("${name}_expire") || 86400; + + $reader->_genericCacheRefresh($name, $expire_time); + my $resources = $reader->{$cache} ||= {}; + + return $resources if scalar keys %$resources; + + my $select = $reader->sqlSelectAll('rkrid, name', 'reskey_resources'); + for (@$select) { + $resources->{id} {$_->[0]} = $_->[1]; + $resources->{name}{$_->[1]} = $_->[0]; + } + + return $resources; +} + +#======================================================================== +sub getChecks { + my($self) = @_; + $self->_flow; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $name = 'reskey_resource_checks'; + my $cache = "_${name}_cache"; + my $cache_time = "_${name}_cache_time"; + my $expire_time = getCurrentStatic("${name}_expire") || 86400; + + $reader->_genericCacheRefresh($name, $expire_time); + my $checks_cache = $reader->{$cache} ||= {}; + + my $checks = $checks_cache->{ $self->type }{ $self->resname }; + return $checks if defined $checks; # could be empty array + + my $type_q = $reader->sqlQuote($self->type); + unless ($self->rkrid && $self->resname) { + return 0; + } + + # this select will group by ordernum, so if there is a conflict, + # the actual type (create, touch, use) will override the "all" + # pseudotype + + # setting a specific ordernum to the classname "" (empty string) + # will effectively disable that check + my $rkrid = $self->rkrid; + my $checks_select = $reader->sqlSelectAllHashref( + 'ordernum', 'class, ordernum', 'reskey_resource_checks', + "rkrid=$rkrid AND (type=$type_q OR type='all')", + "ORDER BY ordernum, type DESC, rkrcid" + ); + + $checks = []; + for my $ordernum (sort { $a <=> $b } keys %$checks_select) { + push @$checks, $checks_select->{$ordernum}{class} + if $checks_select->{$ordernum}{class}; + } + $checks_cache->{ $self->type }{ $self->resname } = $checks; + + unless (@$checks) { + my($type, $resname) = ($self->type, $self->resname); + errorLog("No checks for $type / $resname"); + } + + return $checks; +} + +#======================================================================== +sub getAllCheckVars { + my($self) = @_; + + my $vars = $self->{_check_vars} ||= {}; + return $vars if keys %$vars; + + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + my $all = $reader->sqlSelectAll('rkrid, name, value', 'reskey_vars'); + for my $row (@$all) { + $vars->{ $row->[0] }{ $row->[1] } = $row->[2]; + } + + return $vars; +} + +#======================================================================== +sub getCheckVars { + my($self) = @_; + + if ($self->rkrid) { + my $vars = $self->getAllCheckVars; + return $vars->{ $self->rkrid }; + } + + return; +} + +1; + +__END__ + + +=head1 SEE ALSO + +Slash(3). + +=head1 VERSION + +$Id: Key.pm,v 1.1 2006/07/12 11:41:55 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:56 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:56 +0900 Subject: [Slashdotjp-dev 471] CVS update: slashjp/plugins/ResKey/tasks Message-ID: <20060712114156.1EE752AC10A@users.sourceforge.jp> Index: slashjp/plugins/ResKey/tasks/reskey_purge.pl diff -u /dev/null slashjp/plugins/ResKey/tasks/reskey_purge.pl:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ResKey/tasks/reskey_purge.pl Wed Jul 12 20:41:55 2006 @@ -0,0 +1,25 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: reskey_purge.pl,v 1.1 2006/07/12 11:41:55 sugi Exp $ + +use strict; + +use Slash::Constants qw(:slashd :reskey); + +use vars qw( %task $me ); + +$task{$me}{timespec} = '3 * * * *'; +$task{$me}{timespec_panic_1} = ''; # if panic, this can wait +$task{$me}{fork} = SLASHD_NOWAIT; +$task{$me}{code} = sub { + my($virtual_user, $constants, $slashdb, $user, $info, $gSkin) = @_; + + if (my $reskey = getObject('Slash::ResKey')) { + my $count = $reskey->purge_old || 0; + slashdLog("Purged $count reskeys\n"); + } +}; + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:56 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:56 +0900 Subject: [Slashdotjp-dev 472] CVS update: slashjp/plugins/ResKey/templates Message-ID: <20060712114156.4AC352AC0F4@users.sourceforge.jp> Index: slashjp/plugins/ResKey/templates/data;reskey;default diff -u /dev/null slashjp/plugins/ResKey/templates/data;reskey;default:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ResKey/templates/data;reskey;default Wed Jul 12 20:41:56 2006 @@ -0,0 +1,92 @@ +__section__ +default +__description__ +Repository for random data elements. + +* value = the name of the data element to retrieve + +Each data element may have any number of other variables. +__title__ + +__page__ +reskey +__lang__ +en_US +__name__ +data +__template__ +[% SWITCH value %] + +[%# General %] +[% CASE 'create failed' %] + An unknown error has occurred. Please try again. + +[% CASE 'touch-use failed' %] + This resource is no longer valid. Please return to the beginning and try again. + +[% CASE 'reskey not found' %] + Requested resource is invalid. Please return to the beginning and try again. + + +[%# ACL %] +[% CASE 'has no acl' %] + You do not have the permission required to access this resource. + +[% CASE 'has acl_no' %] + You have been banned from accessing this resource. + + +[%# User %] +[% CASE 'is_admin too low' %] + Only admins may access this resource. + +[% CASE 'is_subscriber too low' %] + Only subscribers may access this resource. + +[% CASE 'seclev too low' %] + You do not have the permission required to access this resource. + +[% CASE 'karma too low' %] + You do not have the permission required to access this resource. + + +[%# AL2 %] +[% CASE 'nosubmit al2 failure' %] + You are not allowed to use this resource. + +[% CASE 'nopost al2 failure' %] + You are not allowed to use this resource. + +[% CASE 'nopostanon al2 failure' %] + You are not allowed to use this resource. + + +[%# Duration %] +[% CASE 'too many uses' %] + You have used this resource too much; please try again later. + +[% CASE 'too many failures' %] + This resource is no longer valid. Please return to the beginning and try again. + +[% CASE 'use duration too short' %] + You must wait a little bit before using this resource; please try again later. + +[% CASE 'creation-use duration too short' %] + You must wait a little bit before using this resource; please try again later. + + +[%# ProxyScan %] +[% CASE 'open proxy' %] + You may not post using an open proxy. + + +[%# Post %] +[% CASE 'post method required' %] + You must access this resource using the appropriate method. + + +[% END %] +__seclev__ +10000 +__version__ +$Id: data;reskey;default,v 1.1 2006/07/12 11:41:56 sugi Exp $ Index: slashjp/plugins/ResKey/templates/reskey_tag;misc;default diff -u /dev/null slashjp/plugins/ResKey/templates/reskey_tag;misc;default:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ResKey/templates/reskey_tag;misc;default Wed Jul 12 20:41:56 2006 @@ -0,0 +1,36 @@ +__section__ +default +__description__ +form.reskey is filtered in filter_params to be [a-zA-Z0-9_], +and rkey.reskey is filtered in key() + +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +reskey_tag +__template__ + +[% this_reskey = ''; + # use the rkey object if it is there, or the form otherwise + IF rkey; + this_reskey = rkey.reskey; + ELSE; + this_reskey = user.state.reskey; + END; + + IF !reskey_label; + reskey_label = 'reskey'; + END; + + IF this_reskey %] + +[% reskey_label = ''; END %] + +__seclev__ +500 +__version__ +$Id: reskey_tag;misc;default,v 1.1 2006/07/12 11:41:56 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:56 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:56 +0900 Subject: [Slashdotjp-dev 473] CVS update: slashjp/plugins/SOAP Message-ID: <20060712114156.77A652AC00E@users.sourceforge.jp> Index: slashjp/plugins/SOAP/PLUGIN diff -u slashjp/plugins/SOAP/PLUGIN:1.2 slashjp/plugins/SOAP/PLUGIN:1.3 --- slashjp/plugins/SOAP/PLUGIN:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/SOAP/PLUGIN Wed Jul 12 20:41:56 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:43 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:56 sugi Exp $ name=SOAP description="SOAP API for Plugins" mysql_dump=mysql_dump.sql Index: slashjp/plugins/SOAP/SOAP.pm diff -u slashjp/plugins/SOAP/SOAP.pm:1.2 slashjp/plugins/SOAP/SOAP.pm:1.3 --- slashjp/plugins/SOAP/SOAP.pm:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/SOAP/SOAP.pm Wed Jul 12 20:41:56 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: SOAP.pm,v 1.2 2004/12/23 20:13:43 oliver Exp $ +# $Id: SOAP.pm,v 1.3 2006/07/12 11:41:56 sugi Exp $ package Slash::SOAP; @@ -14,7 +14,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; =head1 NAME @@ -173,4 +173,4 @@ =head1 VERSION -$Id: SOAP.pm,v 1.2 2004/12/23 20:13:43 oliver Exp $ +$Id: SOAP.pm,v 1.3 2006/07/12 11:41:56 sugi Exp $ Index: slashjp/plugins/SOAP/example_client.pl diff -u slashjp/plugins/SOAP/example_client.pl:1.2 slashjp/plugins/SOAP/example_client.pl:1.3 --- slashjp/plugins/SOAP/example_client.pl:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/SOAP/example_client.pl Wed Jul 12 20:41:56 2006 @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -# $Id: example_client.pl,v 1.2 2004/12/23 20:13:43 oliver Exp $ +# $Id: example_client.pl,v 1.3 2006/07/12 11:41:56 sugi Exp $ use strict; use Data::Dumper; Index: slashjp/plugins/SOAP/mysql_dump.sql diff -u slashjp/plugins/SOAP/mysql_dump.sql:1.2 slashjp/plugins/SOAP/mysql_dump.sql:1.3 --- slashjp/plugins/SOAP/mysql_dump.sql:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/SOAP/mysql_dump.sql Wed Jul 12 20:41:56 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_dump.sql,v 1.2 2004/12/23 20:13:43 oliver Exp $ +# $Id: mysql_dump.sql,v 1.3 2006/07/12 11:41:56 sugi Exp $ # INSERT INTO vars (name, value) VALUES ('soap_enabled', 1); Index: slashjp/plugins/SOAP/soap.pl diff -u slashjp/plugins/SOAP/soap.pl:1.2 slashjp/plugins/SOAP/soap.pl:1.3 --- slashjp/plugins/SOAP/soap.pl:1.2 Fri Dec 24 05:13:43 2004 +++ slashjp/plugins/SOAP/soap.pl Wed Jul 12 20:41:56 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: soap.pl,v 1.2 2004/12/23 20:13:43 oliver Exp $ +# $Id: soap.pl,v 1.3 2006/07/12 11:41:56 sugi Exp $ # NOTE: package Slash::SOAP will be in its own .pm file later, # the SQL at the bottom will be in the schema and dump files, From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:56 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:56 +0900 Subject: [Slashdotjp-dev 474] CVS update: slashjp/plugins/ScheduleShifts/templates Message-ID: <20060712114156.D46122AC0F4@users.sourceforge.jp> Index: slashjp/plugins/ScheduleShifts/templates/data;shifts;default diff -u /dev/null slashjp/plugins/ScheduleShifts/templates/data;shifts;default:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/templates/data;shifts;default Wed Jul 12 20:41:56 2006 @@ -0,0 +1,41 @@ +__section__ +default +__description__ +Repository for random data elements. + +* value = the name of the data element to retrieve + +Each data element may have any number of other variables. +__title__ + +__page__ +shifts +__lang__ +en_US +__name__ +data +__template__ +[% SWITCH value %] + +[% CASE 'page_title' + +-%]Site Editor Schedules[%- + +CASE 'shift_chg_subj'; + + day = day.ucfirst; + shift = shift.ucfirst; + date = date.replace(' 00:00', ''); + IF type == 'default'; + detail="Default $day $shift"; + ELSE; + detail="$date $day $shift"; + END; +-%]Shift Change Notice -- [% detail %]: [% old_nickname %] -> [% new_nickname; + +END %] + +__seclev__ +10000 +__version__ +$Id: data;shifts;default,v 1.1 2006/07/12 11:41:56 sugi Exp $ Index: slashjp/plugins/ScheduleShifts/templates/scheduleForm;shifts;default diff -u /dev/null slashjp/plugins/ScheduleShifts/templates/scheduleForm;shifts;default:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/templates/scheduleForm;shifts;default Wed Jul 12 20:41:56 2006 @@ -0,0 +1,98 @@ +__section__ +default +__description__ +The only page that will be defined in this plugin, this form will allow you +to specify both the default shifts, and any shift changes that will need +to be made in the upcoming weeks (number of weeks on form determined by +constants.sheduleshift_numweeks. +__title__ +Scheduling Form (ScheduleShift) +__page__ +shifts +__lang__ +en_US +__name__ +scheduleForm +__template__ +[% key = "-1"; + author_list.$key = "-"; + + myodd = 'data_hl1'; + myeven = 'data_hl2'; + myweeks = ['Default']; + FOR w = weeks; + myweeks.push(w); + END; + +-%] + +
    + + +[% PROCESS titlebar width=> "100%", title => "$constants.sitename Shifts" %] + + + + + +[%- FOR day = days_of_week -%] + +[%- END -%] + + +[% FOR w = myweeks -%] + + + [% FOR d = days_of_week -%] + [% FOR s = shift_types; + key = "-2"; + + # XXX skip if already past date + def_sel = default_shifts.$d.$s || -1; + cur_sel = shifts.$w.$d.$s || def_sel; + + myauthors = {}; + IF w == myweeks.0; + mylabel = "${d}_${s}"; + + FOR author = author_list.keys; + myauthors.$author = author_list.$author; + END; + + ELSE; + mylabel = "S_${w}_${d}_$s"; + + FOR author = author_list.keys; + IF author == def_sel; + myauthors.$key = author_list.$def_sel; + IF cur_sel == def_sel; + cur_sel = key; + END; + ELSIF author == cur_sel && cur_sel != def_sel; + myauthors.$author = author_list.$author _ ' *'; + ELSE; + myauthors.$author = author_list.$author; + END; + END; + + END; + + Slash.createSelect( + mylabel, + myauthors, cur_sel, 1 + ); + + %]
    + [%- END -%] + + [%- END -%] +
    +[% END %] +
    [% day.ucfirst %]
    [% w %]
    + + +
    +__seclev__ +10000 +__version__ +$Id: scheduleForm;shifts;default,v 1.1 2006/07/12 11:41:56 sugi Exp $ Index: slashjp/plugins/ScheduleShifts/templates/shift_change;shifts;default diff -u /dev/null slashjp/plugins/ScheduleShifts/templates/shift_change;shifts;default:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/templates/shift_change;shifts;default Wed Jul 12 20:41:56 2006 @@ -0,0 +1,83 @@ +__skin__ +default +__description__ +Message that is sent to recipients of shift change notices. + + This data comes from ScheduleShifts: + + old = UID of previous assignment of shift + new = UID of new assignment of shift + default = UID of default assignment of shift + date = Date of new assignment, if not a default assignment. + day = Day of new assignment. + type = Schedule change type ('default' or 'shift'). + shift = Name of shift being changed + + Shift_Default = Constant for $old or $new that represents + "The default user" + Shift_Notset = Constant for $old or $new representing + that no assignment has been made + + Inherent data from Messages. This has been hard to determine + but as near as I can figure out, we have: + + mode = Slash.MSG_MODE_EMAIL or Slash.MSG_MODE_WEB + user = User the message is being sent to (?) + +__title__ +Useless title to template +__page__ +shifts +__lang__ +en_US +__name__ +shift_change +__template__ +[% + IF msg.mode == Slash.MSG_MODE_WEB; + # Set formatting codes for web. + bold=''; unbold=''; break='
    '; + ELSE; + # Set formatting codes for email. + bold='*'; unbold='*'; break="\n"; + END; + + IF user.uid == old; + the_shift = "your $shift"; + ELSE; + IF old > 0; + the_shift = "${old_nickname}'s $shift"; + ELSE; + IF old == Shift_Notset; + the_shift = "the unassigned $shift"; + ELSE; + the_shift = "${old_nickname}'s usual $shift"; + END; + END; + END; + + IF user.uid == new; + new_assign = 'you have'; + ELSE; + new_assign = "${new_nickname} has"; + END; +-%] +[% bold %]NOTICE OF SHIFT CHANGE[% unbold; break; +break -%] +[% IF type == 'default' -%] +Please be aware that [% new_assign %] been assigned[% break; +bold; 'all of '; the_shift; unbold -%] shifts for [% day %].[% +break -%] +[% ELSE -%] +Please be aware that [% new_assign %] been assigned[% break; +bold; the_shift; unbold -%] shift on [% day.ucfirst %][% IF date %], [% +date.replace(' 00:00', ''); END %].[% break; +break -%] +[% END -%] +Make sure you update your calendars appropriately![% +break; +break; -%] +__seclev__ +10000 +__version__ +$Id: shift_change;shifts;default,v 1.1 2006/07/12 11:41:56 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:56 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:56 +0900 Subject: [Slashdotjp-dev 475] CVS update: slashjp/plugins/ScheduleShifts Message-ID: <20060712114156.A6EDC2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/ScheduleShifts/Makefile.PL diff -u /dev/null slashjp/plugins/ScheduleShifts/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/Makefile.PL Wed Jul 12 20:41:56 2006 @@ -0,0 +1,9 @@ +use ExtUtils::MakeMaker; +use DBIx::Password; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Slash::ScheduleShifts', + 'VERSION_FROM' => 'ScheduleShifts.pm', # finds $VERSION + 'PM' => { 'ScheduleShifts.pm' => '$(INST_LIBDIR)/ScheduleShifts.pm' }, +); Index: slashjp/plugins/ScheduleShifts/PLUGIN diff -u /dev/null slashjp/plugins/ScheduleShifts/PLUGIN:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/PLUGIN Wed Jul 12 20:41:56 2006 @@ -0,0 +1,12 @@ +# $Id: PLUGIN,v 1.1 2006/07/12 11:41:56 sugi Exp $ +name=ScheduleShifts +description="set up shifts for editors" + +htdoc=shifts.pl + +template=templates/scheduleForm;shifts;default +template=templates/data;shifts;default +template=templates/shift_change;shifts;default + +mysql_dump=mysql_dump +mysql_prep=mysql_schema Index: slashjp/plugins/ScheduleShifts/ScheduleShifts.pm diff -u /dev/null slashjp/plugins/ScheduleShifts/ScheduleShifts.pm:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/ScheduleShifts.pm Wed Jul 12 20:41:56 2006 @@ -0,0 +1,523 @@ +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: ScheduleShifts.pm,v 1.1 2006/07/12 11:41:56 sugi Exp $ + +package Slash::ScheduleShifts; + +use strict; +use Date::Calc qw(Add_Delta_Days); +use DBIx::Password; +use Slash 2.003; # require Slash 2.3.x +use Slash::Constants qw(:messages); +use Slash::Utility; + +use base 'Exporter'; +use base 'Slash::DB::Utility'; +use base 'Slash::DB::MySQL'; + +use constant SHIFT_DEFAULT => -2; +use constant SHIFT_NOTSET => -1; + +our($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +our @DOW = qw(sun mon tue wed thu fri sat); +our %DOW; +$DOW{$DOW[$_]} = $_ for 0..$#DOW; + +sub getDayOfWeekOffset { + my($self, $day) = @_; + if ($day =~ /\D/) { + return $DOW{$day}; + } else { + return $DOW[$day]; + } +} + + +sub new { + my($class, $user) = @_; + my $self = {}; + + my $plugin = getCurrentStatic('plugin'); + return unless $plugin->{'ScheduleShifts'}; + + bless($self, $class); + $self->{virtual_user} = $user; + $self->sqlConnect; + + my $static_shift_defs = getCurrentStatic('shift_definitions'); + + # What about error handling for bad shift definitions? + # + # How about warnings for overlapping shifts, or should that + # be allowed? Hmmmm..... - Cliff + for (split /:/, $static_shift_defs) { + my($s_name, $s_times) = split /,/, $_; + my($start, $len) = split /=/, $s_times; + + $self->{shift_defs}{$s_name} = { + start => $start, + 'length' => $len, + }; + } + $self->{shift_types} = [ keys %{ $self->{shift_defs} } ]; + + return $self; +} + + +sub getEditors { + my($self) = @_; + + return $self->sqlSelectAllHashrefArray( + 'DISTINCT shifts.uid, nickname, realemail', + 'shifts, users', + 'shifts.uid = users.uid AND shifts.uid > 0' + ) || []; +} + +sub getCurrentDefaultShifts { + my($self) = @_; + + my($results, $returnable); + + # This should only pull records "from" January 1st thru + # January 7th. See the comments in saveDefaultShifts() for + # explanation. + $results = $self->sqlSelectAllHashrefArray( + 'shift, uid, date_format(date, "%a") as dow', + 'shifts', 'type="default"' + ); + + # Map into a more useful form. + $returnable->{lc $_->{dow}}{$_->{'shift'}} = $_->{uid} for @{$results}; + + return $returnable; +} + + +sub saveDefaultShifts { + my($self, $defaults) = @_; + + my $form = getCurrentForm(); + + # For default shifts, we are only concerned with the day of the + # week. To make things easier, we use the last year on which + # January 1st fell on a sunday in order to save these times. + # So all records marked as "default" will fall between January 1st + # and January 7th, 1995. + my $new_defaults; + for (keys %{$form}) { + local $" = '|'; + $new_defaults->{$1}{$2} = $form->{$_} + if /^(@DOW)_(.+)$/; + } + + for my $wkday (keys %{$new_defaults}) { + for my $s (keys %{$new_defaults->{$wkday}}) { + next if $defaults->{$wkday}{$s} == + $new_defaults->{$wkday}{$s}; + + my $q_date = $self->sqlQuote( + sprintf '%4d-%02d-%02d', + Add_Delta_Days( + 1995, 1, 1, + $self->getDayOfWeekOffset($wkday) + ) + ); + + my $s_q = $self->sqlQuote($s); + $self->sqlDelete( + 'shifts', + "type='default' AND date=$q_date AND + shift=$s_q" + ) if $defaults->{$wkday}{$s}; + $self->sqlInsert('shifts', { + -date => $q_date, + uid => $new_defaults->{$wkday}{$s}, + type => 'default', + 'shift' => $s, + }); + + $defaults->{$wkday}{$s} = $new_defaults->{$wkday}{$s}; + + # Send message noting shift change. + $self->sendShiftChangeMessage('default', { + old => $defaults->{$wkday}{$s}, + 'new' => $new_defaults->{$wkday}{$s}, + day => $wkday, + 'shift' => $s, + }); + } + } +} + + +# Getting this data form the DB as opposed to the webheads is arguable, but +# in my opinion safer, since webhead times can shift and if the database time +# skews...well that really doesn't matter. What does matter is consistency, +# and these queries shouldn't put THAT much load on the database, and using +# its times should guarantee said consistency. +sub getCurrentWeek { + my($self, $time) = @_; + + my $date = 'CURDATE()'; + + if ($time && $time !~ /\D/) { + my $new = $self->sqlSelect("FROM_UNIXTIME($time, '%Y-%m-%d')"); + $date = $self->sqlQuote($new) if $new; + } + + my $returnable = $self->sqlSelect( + "DATE_SUB($date, INTERVAL DAYOFWEEK($date)-1 DAY)" + ); + + return $returnable; +} + + +sub getCurrentGregorianWeek { + my($self, $time) = @_; + + my $date = $self->sqlQuote( $self->getCurrentWeek($time) ); + + my $returnable = $self->sqlSelect("TO_DAYS($date)"); + + return $returnable; +} + + +sub getCurrentShifts { + my($self, $nweeks, $time) = @_; + + my($results, $returnable); + + # First and last day of scheduling period. + my $start = $self->sqlQuote($self->getCurrentWeek($time)); + my $ndays = $nweeks * 7 - 1; + my $end = $self->sqlQuote($self->sqlSelect( + "date_add(curdate(), interval $ndays day)" + )); + + $results = $self->sqlSelectAllHashrefArray( + 'shift, uid, + to_days(date_sub(date, interval dayofweek(date)-1 day)) + as week, + date_format(date, "%a") as dow', + 'shifts', + "type='shift' AND date BETWEEN $start AND $end" + ); + + + # Note that MySQL's to_days() uses the first day of 0 AD as a base + # date, but Date::Calc::Add_Delta_Days uses the first day of *1 AD* + # as a base, so we need to compensate when using the value of + # one with the other. + for (@{$results}) { + my $week = sprintf '%4d-%02d-%02d', + Add_Delta_Days(1, 1, 1, $_->{week} - 366); + + $returnable->{$week}{lc $_->{dow}}{$_->{'shift'}} = $_->{uid}; + } + + return $returnable; +} + + +sub saveCurrentShifts { + my($self, $defaults) = @_; + + my $constants = getCurrentStatic(); + my $form = getCurrentForm(); + + my $new_shifts; + for (keys %{$form}) { + local $" = '|'; + $new_shifts->{$1}{$2}{$3} = $form->{$_} + if /^S_([\d\-]+)_(@DOW)_(.+)$/; + } + + my $cur_shifts = $self->getCurrentShifts( + $constants->{shift_schedule_weeks} + ); + + for my $sw (keys %{$new_shifts}) { + $sw =~ /(\d\d\d\d)-(\d\d)-(\d\d)/; + my($sy, $sm, $sdy) = ($1, $2, $3); + for my $sd (keys %{$new_shifts->{$sw}}) { + # $shift_date might not be necessary. + my $shift_date = sprintf '%4d-%02d-%02d 00:00', + Add_Delta_Days( + $sy, $sm, $sdy, + $self->getDayOfWeekOffset($sd) + ); + for my $s (keys %{$new_shifts->{$sw}{$sd}}) { + my $assigned = $new_shifts->{$sw}{$sd}{$s}; + my $current = $cur_shifts->{$sw}{$sd}{$s}; + my $default = $defaults->{$sd}{$s}; + + next if ($current == $assigned) + || (!$current && $assigned == SHIFT_DEFAULT) + || (!$current && $assigned == $default); + + my $q_date = $self->sqlQuote($shift_date); + if (!$current) { + $self->sqlInsert('shifts', { + uid => $assigned, + type => 'shift', + shift => $s, + date => $shift_date, + }); + } else { + my $s_q = $self->sqlQuote($s); + my $where = <sqlDelete( + 'shifts', $where + ) + } else { + $self->sqlUpdate('shifts', + { uid => $assigned }, + $where + ); + } + } + + # Write a message for shift change. + $self->sendShiftChangeMessage('shift', { + old => $current || SHIFT_DEFAULT, + 'new' => $assigned, + day => $sd, + date => $shift_date, + 'shift' => $s, + default => $default, + + 'Shift_Default' => SHIFT_DEFAULT, + 'Shift_Notset' => SHIFT_NOTSET, + }); + } + } + } +} + +sub sendShiftChangeMessage { + my($self, $type, $options) = @_; + my $constants = getCurrentStatic(); + my $messages = getObject('Slash::Messages'); + my(%msg_data) = %{$options}; + + # This may be rather squeamish, but I prefer to keep DB calls out + # of templates. + if ($options->{default}) { + $msg_data{default_nickname} = ($options->{default} == SHIFT_NOTSET) + ? 'unassigned' + : $self->getUser($options->{default}, 'nickname'); + } + + $msg_data{old_nickname} = ($options->{old} == SHIFT_DEFAULT) + ? $msg_data{default_nickname} # 'default' + : ($options->{old} == SHIFT_NOTSET) + ? 'unassigned' + : $self->getUser($options->{old}, 'nickname'); + + $msg_data{new_nickname} = ($options->{'new'} == SHIFT_DEFAULT) + ? $msg_data{default_nickname} # 'default' + : ($options->{'new'} == SHIFT_NOTSET) + ? 'unassigned' + : $self->getUser($options->{'new'}, 'nickname'); + + $msg_data{subject} = getData('shift_chg_subj', { + type => $type, + %msg_data, + }); + + # The people who receive this message: + # - The person who had the old shift + # - The person who has the new shift + # - And any designated managers who don't match the + # first two. For now, managers should be designated + # by UID. + my @recipients; + push @recipients, ($options->{old}, $options->{'new'}) + if $constants->{shift_change_message_users}; + for (split /,\s*/, $constants->{shift_change_managers}) { + next if $_ < 0; + push @recipients, $_ if /^\d+$/ && + $_ != $options->{old} && + $_ != $options->{'new'}; + } + + if ($messages) { + # Use site-based communications. + $msg_data{template_name} = 'shift_change'; + $msg_data{template_page} = 'shifts'; + + for (@recipients) { + next unless $_ > 0; + $messages->create( + $_, MSG_CODE_SCHEDULECHG, \%msg_data + ) + } + } else { + # Email message outside of Slash::Messages + # using Mail::Sendmail + my $msg_body = slashDisplay('shift_change', { + %msg_data, + }, 1); + + for (@recipients) { + next if $_ < 0; + my $sendto = $self->getUser($_, 'realemail'); + + sendEmail($sendto, $msg_data{subject}, $msg_body); + } + } +} + + +sub getShift { + my($self, $when) = @_; + $when ||= ''; + my $constants = getCurrentStatic(); + + my $tzcode = $constants->{shift_shifts_tz}; + + # hr begin in our defined TZ, length in hours + my @shifts = map { + [ @{ %{ $self->{shift_defs}{$_} } }{qw(start length)} ] + } @{ $self->{shift_types} }; + + # we only need to find out needed week, day of week, and hour + # if we need today/tomorrow/$x days, don't need hour + + my $fakeuser = { tzcode => $tzcode }; + setUserDate($fakeuser); + + my $time = ($when =~ /^\d+$/) ? ($when || time()) : time(); + $time += $fakeuser->{off_set}; + if (lc($when) =~ /^(-?\d+) (seconds?|minutes?|hours?)$/) { + my($seconds, $unit) = ($1, $2); + $seconds *= 60 if $unit =~ /^minutes?$/; + $seconds *= 3600 if $unit =~ /^hours?$/; + $time += $seconds; + } + if ($when =~ /^(-?\d+) seconds$/i) { + $time += $1; + } + if ($when =~ /^(-?\d+) seconds$/i) { + $time += $1; + } + my @time = localtime($time); + my $dow = $time[6]; + my $day = $self->getDayOfWeekOffset($dow); + + my(@slots, $days); + + if (lc($when) =~ /^(now|next|today|tomorrow|-?\d+ days?)$/) { + $when = $1; + if ($when =~ /^(-?\d+) days?$/) { + $days = $1; + } elsif ($when eq 'today') { + $days = 0; + } elsif ($when eq 'tomorrow') { + $days = 1; + } + } + + if (defined $days) { + if ($days) { + $time += 86400 * $days; + @time = localtime($time); + $dow = $time[6]; + $day = $self->getDayOfWeekOffset($dow); + } + @slots = 0 .. $#{ $self->{shift_types} }; + } else { + my $slot; + my $hr = $time[2]; + # these two are same for 'now' or 'next' + if ($hr < $shifts[0][0]) { + $slot = 0; + # XXX at some point, we should make it return "no current shift + # holder", perhaps optionally? + } elsif ($hr >= ($shifts[-1][0] + $shifts[-1][1])) { + # go to first shift on next day + $time += 86400; + @time = localtime($time); + $dow = $time[6]; + $day = $self->getDayOfWeekOffset($dow); + $hr = 0; + $slot = 0; + } + + unless (defined $slot) { + for my $i (0 .. $#shifts) { + my $shift = $shifts[$i]; + if ($hr >= $shift->[0] && $hr < ($shift->[0] + $shift->[1])) { + $slot = $i; + } + last if defined $slot; + } + + if ($when eq 'now') { + # we have it + } elsif ($when eq 'next') { + if (++$slot > $#{ $self->{shift_types} }) { + $time += 86400; + @time = localtime($time); + $dow = $time[6]; + $day = $self->getDayOfWeekOffset($dow); + $hr = 0; + $slot = 0; + } + } + } + + if (!defined $slot) { + warn "how did we get here? $hr!"; + $slot = 0; + } + + @slots = $slot; + } + return($time, $day, \@slots); +} + + +sub getDaddy { + my($self, $when) = @_; + my $constants = getCurrentStatic(); + my $slashdb = getCurrentDB(); + + my($time, $day, $slots) = $self->getShift($when); + + my $default = $self->getCurrentDefaultShifts; + my $current = $self->getCurrentShifts($constants->{shift_schedule_weeks}, $time); + my $week = $self->getCurrentWeek($time); + + my @daddies = map { + my $uid = $_; + my $u = $slashdb->getUser($uid); + my $data = { + uid => $uid, + + }; + if ($uid > 0) { + $data->{nickname} = $u->{nickname}; + $data->{realemail} = $u->{realemail}; + } + $data; + } map { + $current->{$week}{$day}{ $self->{shift_types}[$_] } || + $default->{$day}{ $self->{shift_types}[$_] } + } @$slots; + + return \@daddies; +} + +1; Index: slashjp/plugins/ScheduleShifts/mysql_dump diff -u /dev/null slashjp/plugins/ScheduleShifts/mysql_dump:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/mysql_dump Wed Jul 12 20:41:56 2006 @@ -0,0 +1,8 @@ +# $Id: mysql_dump,v 1.1 2006/07/12 11:41:56 sugi Exp $ +INSERT INTO message_codes (code, type, seclev) VALUES (17, 'Schedule Change Notification', 100); + +INSERT INTO vars (name, value, description) VALUES ('shift_change_managers', '', 'Comma separated list of user IDs that have been designated as "Shift Change Managers," who will receive a copy of all shift change notices'); +INSERT INTO vars (name, value, description) VALUES ('shift_change_message_users', '1', 'Send messages to users who gain/lose shifts'); +INSERT INTO vars (name, value, description) VALUES ('shift_schedule_weeks', 5, 'Number of weeks in advance in which shifts can be schedules'); +INSERT INTO vars (name, value, description) VALUES ('shift_shifts_tz', 'EST', 'Time zone that the shifts are in'); +INSERT INTO vars (name, value, description) VALUES ('shift_definitions', 'morning,6=6:afternoon,12=6:evening,18=6', 'Shift descriptions which contain colon separated triplets of ", ="'); Index: slashjp/plugins/ScheduleShifts/mysql_schema diff -u /dev/null slashjp/plugins/ScheduleShifts/mysql_schema:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/mysql_schema Wed Jul 12 20:41:56 2006 @@ -0,0 +1,11 @@ +# $Id: mysql_schema,v 1.1 2006/07/12 11:41:56 sugi Exp $ +CREATE TABLE shifts ( + date DATETIME, + uid MEDIUMINT(8), + type ENUM('shift', 'default'), + shift ENUM('morning', 'afternoon', 'evening'), + last_changed TIMESTAMP, + INDEX byuser (uid), + INDEX bytime (last_changed), + INDEX byshift (shift, uid, type) +) TYPE=InnoDB; Index: slashjp/plugins/ScheduleShifts/shifts.pl diff -u /dev/null slashjp/plugins/ScheduleShifts/shifts.pl:1.1 --- /dev/null Wed Jul 12 20:41:56 2006 +++ slashjp/plugins/ScheduleShifts/shifts.pl Wed Jul 12 20:41:56 2006 @@ -0,0 +1,180 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: shifts.pl,v 1.1 2006/07/12 11:41:56 sugi Exp $ + +# shifts.pl -- Part of the ScheduleShifts plugin. + +use strict; + +use Date::Calc qw(Add_Delta_Days); + +use Slash 2.003; # require Slash 2.3.x +use Slash::Constants qw(:web); +use Slash::Display; +use Slash::Utility; +use Slash::XML; +use vars qw($VERSION); + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +sub main { + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $gSkin = getCurrentSkin(); + my $schedule = getObject('Slash::ScheduleShifts'); + + my $admin = $user->{seclev} >= 500; + my $shifts = $user->{seclev} >= 100 || $user->{acl}{shifts}; + + my %ops = ( + show => [ $admin, \&showShifts ], + save => [ $admin, \&saveShifts ], + default => [ $admin, \&showShifts ], + daddy => [ $shifts, \&getDaddyList ], + lcr => [ $shifts, \&setLCR ], + remark => [ $shifts, \&createRemark ], + ); + + my $op = $form->{op}; + + if (!$op || !exists $ops{$op} || !$ops{$op}[ALLOWED]) { + $op = 'default'; + if (!exists $ops{$op} || !$ops{$op}[ALLOWED]) { + redirect($gSkin->{rootdir}); + return; + } + } + + if ($op ne 'daddy' && $op ne 'remark') { + header(getData('page_title')) or return; + } + + # dispatch of op + $ops{$op}[FUNCTION]->($slashdb, $constants, $user, $form, $gSkin, $schedule); + + if ($op ne 'daddy' && $op ne 'remark') { + # writeLog('SOME DATA'); # if appropriate + footer(); + } +} + + +sub setLCR { + my($slashdb, $constants, $user, $form, $gSkin, $schedule) = @_; + + my $lcr_tag = $form->{tag}; + my $lcr_site = $form->{site}; + + $slashdb->setVar("ircslash_lcr_$lcr_site", $slashdb->getTime . "|$lcr_tag"); +} + + +sub createRemark { + my($slashdb, $constants, $user, $form, $gSkin, $schedule) = @_; + + my($remark) = $form->{remark}; + my $remarks = getObject('Slash::Remarks'); + $remarks->createRemark($remark, { type => 'system' }); + 1; +} + + +sub getDaddyList { + my($slashdb, $constants, $user, $form, $gSkin, $schedule) = @_; + + my $daddies = $schedule->getDaddy($form->{when}); + my $when = $form->{when} || 'now'; + my @items; + + my $link = "$gSkin->{absolutedir}/admin.pl"; + + my $shift_types = @$daddies > 1 + ? $schedule->{shift_types} + : [ $when ]; + + my $editors = $schedule->getEditors; + my $all = join ', ', map { "<$_->{realemail}>" } grep { $_->{realemail} } @$editors; + + for (0 .. $#{$shift_types}) { + my $shift = $shift_types->[$_]; + my $daddy = $daddies->[$_]; + + my $item = { + title => $shift, + 'link' => $link + }; + if ($daddy->{uid} > 0) { + $item->{description} = "$daddy->{nickname} <$daddy->{realemail}>"; + } else { + $item->{description} = "unassigned $all"; + } + + push @items, $item; + } + + $form->{content_type} ||= 'rss'; + xmlDisplay($form->{content_type} => { + channel => { + title => "$constants->{sitename} shifts for $when", + 'link' => $link, + }, + items => \@items, + rdfitemdesc => 1, + rdfitemdesc_html => 1, + }); +} + + +sub saveShifts { + my($slashdb, $constants, $user, $form, $gSkin, $schedule) = @_; + my $defaults = $schedule->getCurrentDefaultShifts; + + $schedule->saveDefaultShifts($defaults); + $schedule->saveCurrentShifts($defaults); + + showShifts(@_); +} + + +sub showShifts { + my($slashdb, $constants, $user, $form, $gSkin, $schedule) = @_; + + my $authors = $slashdb->getDescriptions('authors', '', 1); + my $defaults = $schedule->getCurrentDefaultShifts || {}; + my $num_weeks = $constants->{shift_schedule_weeks}; + my $shifts = $schedule->getCurrentShifts($num_weeks); + + my $schedule_weeks; + my $cur_week = $schedule->getCurrentGregorianWeek; + for (0 .. $num_weeks) { + push @{$schedule_weeks}, sprintf('%4d-%02d-%02d', + # Adjust $cur_week to 1 AD base. + Add_Delta_Days(1, 1, 1, ($cur_week - 366) + $_ * 7) + ); + } + + my @dow = map { $schedule->getDayOfWeekOffset($_) } 0..6; + + my($time, $day, $slots) = $schedule->getShift; + + slashDisplay('scheduleForm', { + # we will be modifying it + author_list => { %$authors }, + days_of_week => \@dow, + default_shifts => $defaults, + shifts => $shifts, + shift_types => $schedule->{shift_types}, + weeks => $schedule_weeks, + curr_day => $day, + }); +} + + +createEnvironment(); +main(); + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:57 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:57 +0900 Subject: [Slashdotjp-dev 476] CVS update: slashjp/plugins/Search Message-ID: <20060712114157.0DD5A2AC00E@users.sourceforge.jp> Index: slashjp/plugins/Search/MANIFEST diff -u slashjp/plugins/Search/MANIFEST:1.1.1.1 slashjp/plugins/Search/MANIFEST:1.2 --- slashjp/plugins/Search/MANIFEST:1.1.1.1 Wed Jan 28 06:55:06 2004 +++ slashjp/plugins/Search/MANIFEST Wed Jul 12 20:41:56 2006 @@ -1,4 +1,3 @@ -Changes MANIFEST Makefile.PL PLUGIN Index: slashjp/plugins/Search/PLUGIN diff -u slashjp/plugins/Search/PLUGIN:1.3 slashjp/plugins/Search/PLUGIN:1.4 --- slashjp/plugins/Search/PLUGIN:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/PLUGIN Wed Jul 12 20:41:56 2006 @@ -1,6 +1,7 @@ -# $Id: PLUGIN,v 1.3 2004/12/31 12:37:14 oliver Exp $ +# $Id: PLUGIN,v 1.4 2006/07/12 11:41:56 sugi Exp $ name=Search htdoc=search.pl +css=search.css mysql_dump=dump mysql_prep=mysql_prep description=Slash Search is the default search engine for Slash. Index: slashjp/plugins/Search/Search.pm diff -u slashjp/plugins/Search/Search.pm:1.3 slashjp/plugins/Search/Search.pm:1.4 --- slashjp/plugins/Search/Search.pm:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/Search.pm Wed Jul 12 20:41:56 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Search.pm,v 1.3 2004/12/31 12:37:14 oliver Exp $ +# $Id: Search.pm,v 1.4 2006/07/12 11:41:56 sugi Exp $ package Slash::Search; @@ -11,7 +11,7 @@ use vars qw($VERSION); use base 'Slash::DB::Utility'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # FRY: And where would a giant nerd be? THE LIBRARY! @@ -75,7 +75,7 @@ my $gSkin = getCurrentSkin(); my $reader = getObject('Slash::DB', { db_type => 'reader' }); my $skin = $reader->getSkin($form->{section} || $gSkin->{skid}); - if ($skin->{skid} != $constants->{mainpage_skid}) { + if ($skin->{skid} && $skin->{skid} != $constants->{mainpage_skid}) { $where .= " AND primaryskid = $skin->{skid}"; } @@ -150,7 +150,7 @@ $columns .= ", TRUNCATE((( " . $self->_score('title', $form->{query}, $constants->{search_method}) . " + " . $self->_score('introtext,bodytext', $form->{query}, $constants->{search_method}) .") / 2), 1) AS score " } - my $tables = "stories, story_text LEFT JOIN story_param ON stories.stoid=story_param.stoid AND story_param.name='neverdisplay'"; + my $tables = "story_text, stories LEFT JOIN story_param ON stories.stoid=story_param.stoid AND story_param.name='neverdisplay'"; my $other = ''; $other .= " HAVING score > 0 " @@ -181,9 +181,17 @@ my $gSkin = getCurrentSkin(); my $reader = getObject('Slash::DB', { db_type => 'reader' }); + + if (@{$constants->{search_ignore_skids}}) { + my $skid_list = join ',', + map { $reader->sqlQuote($_) } + grep { $_ != $gSkin->{skid} } # allow searching on THIS skid + @{$constants->{search_ignore_skids}}; + $where .= " AND primaryskid NOT IN ($skid_list) "; + } - my $skin = $reader->getSkin($form->{section}); - $skin ||= $reader->getSkin($gSkin->{skid} || $constants->{mainpage_skid}); + my $skin = $reader->getSkin($form->{section} || $gSkin->{skid}); + $skin ||= $constants->{mainpage_skid}; if ($skin->{skid} && $skin->{skid} != $constants->{mainpage_skid}) { # XXXSKIN this is wrong, we want to join on story_topics_rendered # by putting $skin->{nexus} into the list of tids we demand @@ -200,7 +208,7 @@ # one select to pull out *all* sids with the topic(s) in question, # and then not join on story_topics, just use a "sid IN" clause. # The problem is that, for large topics, this may be very many sids; - # on OSDN sites, we're seeing some topics with 4,000 to 13,000 + # on OSTG sites, we're seeing some topics with 4,000 to 13,000 # stories in them. That makes the SELECT too large to be efficient. # So I'm fixing this in a not very good way: limiting the number # of stories we search, on any search that includes a topic @@ -228,9 +236,10 @@ } my $string = join(',', @{$self->sqlQuote(\@tids)}); if ($constants->{topic_search_use_join}) { - $tables.= " LEFT JOIN story_topics_rendered ON stories.stoid = story_topics_rendered.stoid"; -# XXXSKIN - no more id in schema, just yank? -# $where .= " AND story_topics_rendered.id IS NOT NULL"; + # XXX I haven't looked closely at this but at first + # glance I'm not sure why this is a LEFT JOIN and + # not an ordinary inner join. - Jamie 2005/12/16 + $tables .= " LEFT JOIN story_topics_rendered ON stories.stoid = story_topics_rendered.stoid"; $where .= " AND story_topics_rendered.tid IN ($string)"; $other = "GROUP by stoid $other"; } else { Index: slashjp/plugins/Search/dump diff -u slashjp/plugins/Search/dump:1.3 slashjp/plugins/Search/dump:1.4 --- slashjp/plugins/Search/dump:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/dump Wed Jul 12 20:41:56 2006 @@ -1,5 +1,5 @@ # -# $Id: dump,v 1.3 2004/12/31 12:37:14 oliver Exp $ +# $Id: dump,v 1.4 2006/07/12 11:41:56 sugi Exp $ # INSERT INTO vars (name, value, description) VALUES ('search_default_display', '30', 'Default number of entries to display on Search page'); @@ -26,3 +26,6 @@ # i am hoping to make it so we can just do something like # "search/SOAP_speed_limit" instead ... we'll see #INSERT INTO vars (name, value) VALUES ('test/get_uid_speed_limit', 10); + + +INSERT INTO css (rel, type, media, file, title, skin, page, admin, theme, ctid, ordernum, ie_cond) VALUES ('stylesheet','text/css','screen, projection','search.css','','','search','no','',2,0, ''); Index: slashjp/plugins/Search/mysql_prep diff -u slashjp/plugins/Search/mysql_prep:1.3 slashjp/plugins/Search/mysql_prep:1.4 --- slashjp/plugins/Search/mysql_prep:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/mysql_prep Wed Jul 12 20:41:56 2006 @@ -1,13 +1,21 @@ # -# $Id: mysql_prep,v 1.3 2004/12/31 12:37:14 oliver Exp $ +# $Id: mysql_prep,v 1.4 2006/07/12 11:41:56 sugi Exp $ # -ALTER TABLE story_text ADD FULLTEXT title (title), ADD FULLTEXT intro_body (introtext,bodytext); -ALTER TABLE comments add fulltext (subject); -ALTER TABLE comment_text add fulltext (comment); +# If you are using a replicated slave to search on, which we +# recommend, you need only perform these ALTERs on the slave. +# Replication from an InnoDB master to a MyISAM slave works. + +# XXX Also, see the comment re LOCK IN SHARE MODE in MySQL.pm +# setCommentForMod(). + +ALTER TABLE story_text Type=MyISAM, ADD FULLTEXT title (title), ADD FULLTEXT intro_body (introtext,bodytext); +ALTER TABLE comments Type=MyISAM, ADD FULLTEXT subject (subject); +ALTER TABLE comment_text Type=MyISAM, ADD FULLTEXT (comment); # ALTER TABLE blocks add fulltext (description,title,block); -ALTER TABLE users add fulltext (nickname); -ALTER TABLE pollquestions add fulltext (question); -ALTER TABLE journals add fulltext (description); -ALTER TABLE journals_text add fulltext (article); -#ALTER TABLE submissions add fulltext (subj,story); +ALTER TABLE users Type=MyISAM, ADD FULLTEXT (nickname); +ALTER TABLE pollquestions Type=MyISAM, ADD FULLTEXT (question); +ALTER TABLE journals Type=MyISAM, ADD FULLTEXT (description); +ALTER TABLE journals_text Type=MyISAM, ADD FULLTEXT (article); +#ALTER TABLE submissions Type=MyISAM, ADD FULLTEXT (subj,story); + Index: slashjp/plugins/Search/search.css diff -u /dev/null slashjp/plugins/Search/search.css:1.1.2.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/Search/search.css Wed Jul 12 20:41:56 2006 @@ -0,0 +1,28 @@ +#search legend +{ + display: none; +} +#search fieldset +{ + margin: 0; + padding: 0; + border: none; +} + +#search form { margin: 0 0 1em 0; } +.search-results .data { font-size: 80%; } + +.search-results .details +{ + font-size: 80%; + margin: 0 0 1em 0; +} + +.sectiontitle li { + font-size: 80%; +} + +.search-results .author { + font-size: 80%; + margin: 0 0 1em 0; +} Index: slashjp/plugins/Search/search.pl diff -u slashjp/plugins/Search/search.pl:1.4 slashjp/plugins/Search/search.pl:1.5 --- slashjp/plugins/Search/search.pl:1.4 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/search.pl Wed Jul 12 20:41:56 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: search.pl,v 1.4 2004/12/31 12:37:14 oliver Exp $ +# $Id: search.pl,v 1.5 2006/07/12 11:41:56 sugi Exp $ use strict; use Slash; @@ -35,6 +35,7 @@ my $constants = getCurrentStatic(); my $form = getCurrentForm(); my $user = getCurrentUser(); + setCurrentSkin(determineCurrentSkin()); my $gSkin = getCurrentSkin(); my $slashdb = getCurrentDB(); my $searchDB = getObject('Slash::Search', { db_type => 'search' }); @@ -53,6 +54,9 @@ # switch search mode to poll if in polls skin and other # search type isn't specified +# I've caught gSkin being {} here, on a test box. Not sure if that's a +# bug or just a misconfiguration of mine. - Jamie 2005-11-26 +use Data::Dumper; print STDERR "search.pl gSkin: " . Dumper($gSkin) if !$gSkin->{name}; if ($gSkin->{name} eq 'polls' && !$form->{op}) { $form->{op} = 'polls'; $form->{section} = ''; @@ -70,7 +74,7 @@ unless $constants->{submiss_view}; } - if ($form->{content_type} eq 'rss') { + if ($form->{content_type} && $form->{content_type} =~ $constants->{feed_types}) { # Here, panic mode is handled within the individual funcs. # We want to return valid (though empty) RSS data even # when search is down. @@ -81,6 +85,7 @@ my $header_title = getData('search_header_title', { text => $text }); my $titlebar_title = getData('search_titlebar_title', { text => $text }); header($header_title) or return; + print getData("search_slashboxes"); titlebar("100%", $titlebar_title); $form->{op} = 'stories' unless exists $ops{$form->{op}}; @@ -153,9 +158,9 @@ my $x = ""; $x = $form->{$_} if defined $form->{$_} && $x eq ""; $x =~ s/ /+/g; - $uri .= "$_=$x&" unless $x eq ""; + $uri .= "$_=$x&" unless $x eq ""; } - $uri =~ s/&$//; + $uri =~ s/&$//; return fixurl($uri); } @@ -172,10 +177,11 @@ 'threshold', $formats, $form->{threshold}, 1 ); + my $topic_ref = $form->{tid} ? $slashdb->getTopic($form->{tid}) : { }; slashDisplay('searchform', { # sections => 1, # _skins(), # topics => 1, # _topics(), - tref => $slashdb->getTopic($form->{tid}), + tref => $topic_ref, op => $form->{op}, 'sort' => _sort(), threshhold => 1, @@ -268,10 +274,11 @@ my $start = $form->{start} || 0; my $stories = $searchDB->findStory($form, $start, $constants->{search_default_display} + 1, $form->{sort}); + my $topic_ref = $form->{tid} ? $slashdb->getTopic($form->{tid}) : { }; slashDisplay('searchform', { sections => 1, # _skins(), topics => 1, # _topics(), - tref => $slashdb->getTopic($form->{tid}), + tref => $topic_ref, op => $form->{op}, authors => _authors(), 'sort' => _sort(), @@ -321,11 +328,12 @@ my $start = $form->{start} || 0; my $polls = $searchDB->findPollQuestion($form, $start, $constants->{search_default_display} + 1, $form->{sort}); + my $topic_ref = $form->{tid} ? $slashdb->getTopic($form->{tid}) : { }; slashDisplay('searchform', { op => $form->{op}, # topics => 1, # _topics(), # sections => 1, # _skins(), - tref => $slashdb->getTopic($form->{tid}), + tref => $topic_ref, 'sort' => _sort(), }); @@ -375,16 +383,20 @@ $comments = $searchDB->findComments($form, $start, 15, $form->{sort}); } + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my @items; for my $entry (@$comments) { my $time = timeCalc($entry->{date}); push @items, { title => "$entry->{subject} ($time)", + time => $entry->{date}, + creator => $reader->getUser($entry->{uid}, 'nickname'), 'link' => ($gSkin->{absolutedir} . "/comments.pl?sid=$entry->{did}&cid=$entry->{cid}"), }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} Comment Search", 'link' => "$gSkin->{absolutedir}/search.pl", @@ -412,11 +424,12 @@ my $time = timeCalc($entry->{journal_last_entry_date}); push @items, { title => $entry->{nickname}, + time => $entry->{journal_last_entry_date}, 'link' => ($gSkin->{absolutedir} . '/users.pl?nick=' . $entry->{nickname}), }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} User Search", 'link' => "$gSkin->{absolutedir}/search.pl", @@ -439,6 +452,8 @@ $stories = $searchDB->findStory($form, $start, 15, $form->{sort}); } + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my @items; for my $entry (@$stories) { my $time = timeCalc($entry->{time}); @@ -446,12 +461,14 @@ # so why didn't make it sectional? push @items, { title => $entry->{title}, + time => $entry->{time}, + creator => $reader->getUser($entry->{uid}, 'nickname'), 'link' => ($gSkin->{absolutedir} . '/article.pl?sid=' . $entry->{sid}), description => $entry->{introtext} }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} Story Search", 'link' => "$gSkin->{absolutedir}/search.pl", @@ -483,11 +500,12 @@ my $link = $url || $gSkin->{absolutedir}; push @items, { title => "$entry->{question} ($time)", + time => $entry->{date}, 'link' => ($link . '/pollBooth.pl?qid=' . $entry->{qid}), }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} Poll Search", 'link' => "$gSkin->{absolutedir}/search.pl", @@ -559,12 +577,14 @@ my $time = timeCalc($entry->{date}); push @items, { title => "$entry->{description} ($time)", + time => $entry->{date}, + creator => $entry->{nickname}, 'link' => ($gSkin->{absolutedir} . '/~' . fixparam($entry->{nickname}) . '/journal/' . $entry->{id}), description => $constants->{article}, }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} Journal Search", 'link' => "$gSkin->{absolutedir}/search.pl", @@ -583,12 +603,13 @@ my $start = $form->{start} || 0; my $entries = $searchDB->findSubmission($form, $start, $constants->{search_default_display} + 1, $form->{sort}); + my $topic_ref = $form->{tid} ? $slashdb->getTopic($form->{tid}) : { }; slashDisplay('searchform', { op => $form->{op}, sections => 1, # _skins(), topics => 1, # _topics(), submission_notes => $slashdb->getDescriptions('submission-notes'), - tref => $slashdb->getTopic($form->{tid}), + tref => $topic_ref, 'sort' => _sort(), }); @@ -642,12 +663,13 @@ my $time = timeCalc($entry->{time}); push @items, { title => "$entry->{subj} ($time)", + time => $entry->{time}, 'link' => ($gSkin->{absolutedir} . '/submit.pl?subid=' . $entry->{subid}), 'description' => $entry->{story}, }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} Submission Search", 'link' => "$gSkin->{absolutedir}/search.pl", @@ -676,7 +698,7 @@ # we pop it off if ($entries && @$entries) { for (@$entries) { - $_->{title} = strip_plaintext($_->{introtext}); + $_->{title} = strip_notags($_->{introtext}); $_->{description} = _shorten(strip_notags($_->{description})); } my $forward; @@ -721,12 +743,13 @@ my $time = timeCalc($entry->[2]); push @items, { title => "$entry->{title} ($time)", + time => $entry->[2], 'link' => $entry->{link}, # No, this is not right -Brian 'description' => $entry->{description}, }; } - xmlDisplay(rss => { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} RSS Search", 'link' => "$gSkin->{absolutedir}/search.pl", From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:57 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:57 +0900 Subject: [Slashdotjp-dev 477] CVS update: slashjp/plugins/Search/SOAP Message-ID: <20060712114157.370B22AC0CF@users.sourceforge.jp> Index: slashjp/plugins/Search/SOAP/SOAP.pm diff -u slashjp/plugins/Search/SOAP/SOAP.pm:1.3 slashjp/plugins/Search/SOAP/SOAP.pm:1.4 --- slashjp/plugins/Search/SOAP/SOAP.pm:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/SOAP/SOAP.pm Wed Jul 12 20:41:57 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: SOAP.pm,v 1.3 2004/12/31 12:37:14 oliver Exp $ +# $Id: SOAP.pm,v 1.4 2006/07/12 11:41:57 sugi Exp $ package Slash::Search::SOAP; @@ -11,7 +11,7 @@ use vars qw($VERSION); use base 'Slash::DB::Utility'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # As a note I will be adding support for sort later. # I want to make it easy for people just to pass in a string Index: slashjp/plugins/Search/SOAP/search_client.pl diff -u slashjp/plugins/Search/SOAP/search_client.pl:1.2 slashjp/plugins/Search/SOAP/search_client.pl:1.3 --- slashjp/plugins/Search/SOAP/search_client.pl:1.2 Fri Dec 24 05:13:44 2004 +++ slashjp/plugins/Search/SOAP/search_client.pl Wed Jul 12 20:41:57 2006 @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -# $Id: search_client.pl,v 1.2 2004/12/23 20:13:44 oliver Exp $ +# $Id: search_client.pl,v 1.3 2006/07/12 11:41:57 sugi Exp $ use strict; use Data::Dumper; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:57 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:57 +0900 Subject: [Slashdotjp-dev 478] CVS update: slashjp/plugins/Search/templates Message-ID: <20060712114157.64AEF2AC0F4@users.sourceforge.jp> Index: slashjp/plugins/Search/templates/commentsearch;search;default diff -u slashjp/plugins/Search/templates/commentsearch;search;default:1.2 slashjp/plugins/Search/templates/commentsearch;search;default:1.3 --- slashjp/plugins/Search/templates/commentsearch;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/commentsearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,26 +11,34 @@ __name__ commentsearch __template__ -[% USE Slash %] -

    This search covers only subjects of comments that are posted.

    + +

    +
    + This search covers only subjects of comments that are posted. +
    [% FOREACH comment=comments %] [% user_email = Slash.db.getUser(comment.uid, ['fakeemail', 'nickname']) %] - [% comment.subject %] - - by [% user_email.nickname | strip_literal %] on [% Slash.timeCalc(comment.date) %]
    - - Attached to: [% comment.title %] posted on [% Slash.timeCalc(comment.ts) %]
    +
    +

    + [% comment.subject %] +

    +
    + by [% user_email.nickname | strip_literal %] on [% Slash.timeCalc(comment.date) %] +
    +
    + Attached to: [% comment.title %] posted on [% Slash.timeCalc(comment.ts) %] +
    [% IF comment.score %] - Score: [% comment.score %]
    +
    + Score: [% comment.score %] +
    [% END %] -
    -

    +

    [% END %] [% PROCESS pagination %] -

    - - +

    + __seclev__ 100 __version__ -$Id: commentsearch;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: commentsearch;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/data;search;default diff -u slashjp/plugins/Search/templates/data;search;default:1.4 slashjp/plugins/Search/templates/data;search;default:1.5 --- slashjp/plugins/Search/templates/data;search;default:1.4 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/data;search;default Wed Jul 12 20:41:57 2006 @@ -19,32 +19,46 @@ [% CASE 'nousers' %] [% returnme.data_constant = 1 %] - No usernames were found that match your query. - +
    + No usernames were found that match your query. +
    + [% CASE 'nostories' %] [% returnme.data_constant = 1 %] - No stories were found that match your query. - +
    + No stories were found that match your query. +
    + [% CASE 'nocomments' %] [% returnme.data_constant = 1 %] - No comments were found that match your query. - +
    + No comments were found that match your query. +
    + [% CASE 'nopolls' %] [% returnme.data_constant = 1 %] - No poll questions were found that match your query. - +
    + No poll questions were found that match your query. +
    + [% CASE 'nojournals' %] [% returnme.data_constant = 1 %] - No journals were found to match your query. - +
    + No journals were found to match your query. +
    + [% CASE 'nosubmissions' %] [% returnme.data_constant = 1 %] - No submissions were found to match your query. - +
    + No submissions were found to match your query. +
    + [% CASE 'norss' %] [% returnme.data_constant = 1 %] - No rss entries were found to match your query. - +
    + No rss entries were found to match your query. +
    + [% CASE 'all_sections' %] [% returnme.data_constant = 1 %] All Sections @@ -74,10 +88,11 @@ [% ELSE %] Search [% constants.sitename %] [% END %] - +[% CASE 'search_slashboxes' # Not needed unless you have slashboxes on the search page %] [% END %] + __seclev__ 10000 __version__ -$Id: data;search;default,v 1.4 2004/12/31 12:37:14 oliver Exp $ +$Id: data;search;default,v 1.5 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/journalsearch;search;default diff -u slashjp/plugins/Search/templates/journalsearch;search;default:1.2 slashjp/plugins/Search/templates/journalsearch;search;default:1.3 --- slashjp/plugins/Search/templates/journalsearch;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/journalsearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,23 +11,34 @@ __name__ journalsearch __template__ -[% USE Slash %] + +
    [% FOREACH journal=entries %] - [% journal.description %]
    - On [% Slash.timeCalc(journal.date) %]
    - [% journal.article %]
    - - Author: [% journal.nickname | strip_literal %] - [% IF journal.score %]
    - Score: ([% journal.score %]) - [% END %] -
    -

    +

    +

    + [% journal.description %] +

    +
    + On [% Slash.timeCalc(journal.date) %] +
    +
    + [% journal.article %] +
    + + [% IF journal.score %] +
    + Score: ([% journal.score %]) +
    + [% END %] +
    [% END %] [% PROCESS pagination %] -

    +

    + __seclev__ 100 __version__ -$Id: journalsearch;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: journalsearch;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/nosearch;search;default diff -u slashjp/plugins/Search/templates/nosearch;search;default:1.2 slashjp/plugins/Search/templates/nosearch;search;default:1.3 --- slashjp/plugins/Search/templates/nosearch;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/nosearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,17 +11,19 @@ __name__ nosearch __template__ -

    Sorry, search is down at the moment. + +

    +Sorry, search is down at the moment. Until it's back up, you may wish to search [% constants.sitename %] through Google:
    -
    - - - -
    -

    - +

    + + + +
    + + __seclev__ 100 __version__ -$Id: nosearch;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: nosearch;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/pagination;search;default diff -u slashjp/plugins/Search/templates/pagination;search;default:1.2 slashjp/plugins/Search/templates/pagination;search;default:1.3 --- slashjp/plugins/Search/templates/pagination;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/pagination;search;default Wed Jul 12 20:41:57 2006 @@ -11,19 +11,21 @@ __name__ pagination __template__ + __seclev__ 100 __version__ -$Id: pagination;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: pagination;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/pollsearch;search;default diff -u slashjp/plugins/Search/templates/pollsearch;search;default:1.2 slashjp/plugins/Search/templates/pollsearch;search;default:1.3 --- slashjp/plugins/Search/templates/pollsearch;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/pollsearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,23 +11,32 @@ __name__ pollsearch __template__ + +
    [% FOREACH poll = polls %] - [% skin = Slash.db.getSkin(poll.skin) %] - [% link = skin.url ? skin.url : gSkin.rootdir %] - [% poll.question %]
    - - On [% Slash.timeCalc(poll.date) %]
    - Voters: [% poll.voters %]
    - [% IF poll.score %] + [% skin = Slash.db.getSkin(poll.primaryskid) %] + [% link = skin.rootdir || gSkin.rootdir %] +
    +

    + [% poll.question %] +

    +
    + On [% Slash.timeCalc(poll.date) %] +
    +
    + Voters: [% poll.voters %] +
    + [% IF poll.score %] +
    Score: [% poll.score %] - [% END %] - -

    +

    + [% END %] +
    [% END %] [% PROCESS pagination %] -

    - +

    + __seclev__ 100 __version__ -$Id: pollsearch;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: pollsearch;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/rsssearch;search;default diff -u slashjp/plugins/Search/templates/rsssearch;search;default:1.1.1.1 slashjp/plugins/Search/templates/rsssearch;search;default:1.2 --- slashjp/plugins/Search/templates/rsssearch;search;default:1.1.1.1 Wed Jan 28 06:55:07 2004 +++ slashjp/plugins/Search/templates/rsssearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,22 +11,31 @@ __name__ rsssearch __template__ -[% USE Slash %] +
    [% FOREACH entry=entries %] - [% entry.title %]
    - On [% Slash.timeCalc(entry.created) %] - [% IF entry.description %] - [% entry.description %]...
    - [% END %] - [% IF entry.score %] - Score: [% entry.score %]
    - [% END %] -

    +

    +

    + [% entry.title %] +

    +
    + On [% Slash.timeCalc(entry.created) %] +
    + [% IF entry.description %] +
    + [% entry.description %]... +
    + [% END %] + [% IF entry.score %] +
    + Score: [% entry.score %] +
    + [% END %] +
    [% END %] [% PROCESS pagination %] -

    - +

    + __seclev__ 100 __version__ -$Id: rsssearch;search;default,v 1.1.1.1 2004/01/27 21:55:07 oliver Exp $ +$Id: rsssearch;search;default,v 1.2 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/searchform;search;default diff -u slashjp/plugins/Search/templates/searchform;search;default:1.2 slashjp/plugins/Search/templates/searchform;search;default:1.3 --- slashjp/plugins/Search/templates/searchform;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/searchform;search;default Wed Jul 12 20:41:57 2006 @@ -11,45 +11,45 @@ __name__ searchform __template__ -
    - +
    [% IF tref.image %] - [% tref.alttext %] +
    + + [% tref.alttext %] + +
    [% END %] -
    -
    + +
    + Search [% form.query %] - + [% IF authors %] [% Slash.createSelect("author", authors, form.author, 1, 0, 1) %] [% END %] [% Slash.createSelect("sort", sort, form.sort, 1) %] -
    +
    - Stories - Comments - Users - Polls + Stories + Comments + Users + Polls [% IF constants.search_journal_enabled %] - Journals + Journals [% END %] [% IF constants.rss_store %] [% IF constants.search_rss_enabled || user.is_admin %] - RSS Headlines + RSS Headlines [% END %] [% END %] [% IF constants.submiss_view || user.is_admin %] - Submissions + Submissions [% END %] -
    - +
    [% IF journal_option %] - Users with Journals + Users with Journals [% END %] [% IF submission_notes %] @@ -58,13 +58,13 @@ [% IF threshhold %] Threshold [% threshold_select %] - + [% END %] -

    -

    +
    +
    + [% IF sections || topics %] -
    [% topics = Slash.db.getTopicTree(); @@ -84,7 +84,8 @@ listex = listnames.size mod 3; i = 0; %] -[% constants.sitename %] +
    +[% constants.sitename %] [% IF !topics.${form.tid}.nexus && topics.${form.tid}.parent; thisparent = topics.${form.tid}.parent.keys.nsort.0; IF thisparent == constants.mainpage_nexus_tid; @@ -95,14 +96,12 @@ [% END; END; IF form.tid %] :: [% topics.${form.tid}.textname %] [% END; IF listnames.size %] -Topics +Topics [% END %] -
    [% IF listnames.size %]
    -
      [% FOREACH s = listnames.keys.sort -%]
    • [% s %][% @@ -110,24 +109,22 @@ END %]
    • [%- i = i + 1; IF i == listcount.int || i == 0; - IF i == listcount.int && listex; - listext = listex = 1; + IF i == listcount.int && listex; # do one more line in this row + listex = 1; i = -1; NEXT; END; + i = 0; # end this row %]
    - -
      [% END; END # FOREACH %] +
        [% END; END # FOREACH %]
    [% END # IF listnames.size %] - + [% END # IF sections || topics %] -
    - __seclev__ 100 __version__ -$Id: searchform;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: searchform;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/storysearch;search;default diff -u slashjp/plugins/Search/templates/storysearch;search;default:1.3 slashjp/plugins/Search/templates/storysearch;search;default:1.4 --- slashjp/plugins/Search/templates/storysearch;search;default:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/storysearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,7 +11,9 @@ __name__ storysearch __template__ -[% FOREACH story=stories %] + +
    + [% FOREACH story=stories %] [% skin = Slash.db.getSkin(story.skid); storylinks = Slash.linkStory({ section => skin.name, @@ -21,28 +23,44 @@ 'link' => story.title }) %] -[% storylinks.1 | strip_html %] -[% IF user.is_admin %][ Edit ][% END %] -
    - On [% Slash.timeCalc(story.time, '%B %o, %Y') %] with [% story.commentcount %] comments
    - [% story.introtext %]
    - - [% IF skin.name == 'mainpage' %]Main[% ELSE %][% skin.title %][% END %] > - [% FOREACH tid = story.tids %] - [% topic = Slash.db.getTopic(tid) %] - [% topic.textname %][% ", " UNLESS loop.last %] - [% END %] -
    - [% IF story.score %] - Score: [% story.score %]
    - [% END %] -
    -

    -[% END %] -[% PROCESS pagination %] -

    +

    +

    + + [% storylinks.1 | strip_html %] + + [% IF user.is_admin %] + [ + + Edit + + ] + [% END %] +

    +
    + On [% Slash.timeCalc(story.time, '%B %o, %Y') %] with [% story.commentcount %] comments +
    +
    + [% story.introtext %] +
    +
    + [% IF skin.name == 'mainpage' %]Main[% ELSE %][% skin.title %][% END %] » + [% FOREACH tid = story.tids %] + [% topic = Slash.db.getTopic(tid) %] + [% topic.textname %][% ", " UNLESS loop.last %] + [% END %] +
    + [% IF story.score %] +
    + Score: [% story.score %] +
    + [% END %] +
    + [% END %] + [% PROCESS pagination %] +
    + __seclev__ 100 __version__ -$Id: storysearch;search;default,v 1.3 2004/12/31 12:37:14 oliver Exp $ +$Id: storysearch;search;default,v 1.4 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/subsearch;search;default diff -u slashjp/plugins/Search/templates/subsearch;search;default:1.3 slashjp/plugins/Search/templates/subsearch;search;default:1.4 --- slashjp/plugins/Search/templates/subsearch;search;default:1.3 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/subsearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,34 +11,53 @@ __name__ subsearch __template__ -

    + +

    [% FOREACH entry = entries %] - [% entry.subj %]
    - On [% Slash.timeCalc(entry.time) %]
    - [% entry.story %]
    - +
    +

    + [% entry.subj %] +

    +
    + On [% Slash.timeCalc(entry.time) %] +
    +
    + [% entry.story %] +
    [% submission_state = Slash.db.getDescriptions('submission-state') %] [% skin = Slash.db.getSkin(entry.skid) %] - Section: [% IF skin.name == 'mainpage' %]Main[% ELSE %][% skin.title %][% END %] > +
    + Section: + [% IF skin.name == 'mainpage' %] + Main + [% ELSE %] + [% skin.title %] + [% END %] + > [% FOREACH tid = entry.tid %] [% topic = Slash.db.getTopic(tid) %] - [% topic.textname %][% ", " UNLESS loop.last %] - [% END %]
    - State: [% del = entry.del; submission_state.$del %]
    + [% topic.textname %][% ", " UNLESS loop.last %] + [% END %] +
    +
    + State: [% del = entry.del; submission_state.$del %] +
    [% IF entry.note %] - Note: [% entry.note %]
    +
    + Note: [% entry.note %] +
    [% END %] [% IF entry.score %] - Score: [% entry.score %]
    +
    + Score: [% entry.score %] +
    [% END %] -
    -

    +

    [% END %] -

    [% PROCESS pagination %] -

    - +

    + __seclev__ 100 __version__ -$Id: subsearch;search;default,v 1.3 2004/12/31 12:37:14 oliver Exp $ +$Id: subsearch;search;default,v 1.4 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/Search/templates/usersearch;search;default diff -u slashjp/plugins/Search/templates/usersearch;search;default:1.2 slashjp/plugins/Search/templates/usersearch;search;default:1.3 --- slashjp/plugins/Search/templates/usersearch;search;default:1.2 Fri Dec 31 21:37:14 2004 +++ slashjp/plugins/Search/templates/usersearch;search;default Wed Jul 12 20:41:57 2006 @@ -11,44 +11,39 @@ __name__ usersearch __template__ -[% USE Slash %] - + +
    [% FOREACH thisuser=users %] -
    +
      [% IF thisuser.score %] -
    + [% END %] - + [% IF thisuser.journal_last_entry_date %] - - [% ELSE %] - +
  • + Last Journal entry [% Slash.timeCalc(thisuser.journal_last_entry_date) %] +
  • [% END %] [% UNLESS user.is_anon %] - + [% END %] - + [% END %] -
    +
  • [% thisuser.score %] -
  • - [% thisuser.nickname | strip_literal %]   +
  • + [% thisuser.nickname | strip_literal %]   [% IF thisuser.fakeemail %] - ([% thisuser.uid %]) email: [% thisuser.fakeemail | strip_literal %]
    + ([% thisuser.uid %]) email: [% thisuser.fakeemail | strip_literal %] [% ELSE %] - ([% thisuser.uid %])
    + ([% thisuser.uid %]) [% END %] -
  • - Last Journal entry [% Slash.timeCalc(thisuser.journal_last_entry_date) %] - -   - +
  • [% PROCESS zoo_icons person=thisuser.uid %] -
  • [% PROCESS pagination %] -

    - + + __seclev__ 100 __version__ -$Id: usersearch;search;default,v 1.2 2004/12/31 12:37:14 oliver Exp $ +$Id: usersearch;search;default,v 1.3 2006/07/12 11:41:57 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:57 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:57 +0900 Subject: [Slashdotjp-dev 479] CVS update: slashjp/plugins/SearchToo/SearchToo Message-ID: <20060712114157.C0E5A2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/SearchToo/SearchToo/Classic.pm diff -u /dev/null slashjp/plugins/SearchToo/SearchToo/Classic.pm:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/SearchToo/Classic.pm Wed Jul 12 20:41:57 2006 @@ -0,0 +1,194 @@ +package Slash::SearchToo::Classic; + +use strict; +use Slash::Utility; +use Slash::DB::Utility; +use vars qw($VERSION); +use base 'Slash::DB::Utility'; +use base 'Slash::SearchToo'; + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +# FRY: I did it! And it's all thanks to the books at my local library. + +################################################################# +sub new { + my($class, $user) = @_; + my $self = {}; + + my $plugin = getCurrentStatic('plugin'); + return unless $plugin->{'Search'}; + + bless($self, $class); + $self->{virtual_user} = $user; + $self->sqlConnect(); + + return $self; +} + +################################################################# +sub getOps { + my %ops = ( + stories => 1, + comments => 1, + journals => 1, + polls => 1, + users => 1, + submissions => 1, + test => \&testSearch, + ); + return \%ops; +} + +################################################################# +sub findRecords { + my($self, $type, $query, $opts) = @_; + + my(%processed); + my $results = {}; + my $records = []; + + my $constants = getCurrentStatic(); + my $oldsearch = getObject('Slash::Search', { db_type => 'search' }); + + + ### set up common query terms + my %terms = ( + query => $query->{query}, + ); + + if ($query->{topic}) { + my @topics = ref $query->{topic} + ? @{$query->{topic}} + : $query->{topic}; + $processed{tid} = $topics[0] if @topics; + # API is expecting multiple args in _multi, so we fake it + $processed{_multi}{tid} = \@topics if @topics > 1; + } + + if ($query->{section}) { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + # get section name, for most compatibility with this API + my $skin = $reader->getSkin($query->{section}); + $processed{section} = $skin->{name} if $skin && $skin->{name}; + } + + for (qw(uid author submitter)) { + $processed{$_} = $query->{$_} if $query->{$_} && $query->{$_} =~ /^\d+$/; + } + + + ### set up common options + # old API cannot tell us total or matches + # undef if we cannot find for sure, or if not applicable + my $total = undef; + my $matches = undef; + my $start = $opts->{records_start} || 0; + my $max = $opts->{records_max} || $constants->{search_default_display}; + # if we are not getting total number of matches, fetch an extra so we + # know if there are more, for pagination purposes + $max++ if !defined $matches; + + # sort can be an arrayref, but old API can handle only one + my $sort = ref $opts->{sort} ? $opts->{sort}[0] : $opts->{sort}; + $sort = ($opts->{sort} eq 'date' || $opts->{sort} eq 1) ? 1 : + ($opts->{sort} eq 'relevance' || $opts->{sort} eq 2) ? 2 : + 0; + +### options not used in this backend +# date_start => '', date_end => '', + + + ### dispatch to different queries + if ($type eq 'stories') { + for (qw(tid _multi section author submitter)) { + $terms{$_} = $processed{$_} if $processed{$_}; + } + + $records = $oldsearch->findStory(\%terms, $start, $max, $sort); + } + + elsif ($type eq 'comments') { + for (qw(section)) { + $terms{$_} = $processed{$_} if $processed{$_}; + } + %terms = (%terms, + sid => $query->{sid}, + threshold => $query->{points_min}, + ); + + $records = $oldsearch->findComments(\%terms, $start, $max, $sort); + } + + elsif ($type eq 'journals') { + for (qw(tid uid)) { + $terms{$_} = $processed{$_} if $processed{$_}; + } + + $records = $oldsearch->findJournalEntry(\%terms, $start, $max, $sort); + } + + elsif ($type eq 'polls') { + for (qw(tid section uid)) { + $terms{$_} = $processed{$_} if $processed{$_}; + } + + $records = $oldsearch->findPollQuestion(\%terms, $start, $max, $sort); + } + + elsif ($type eq 'users') { + # sigh, why is this ONE method passing info in an additional parameter? + $records = $oldsearch->findUsers(\%terms, $start, $max, $sort, $query->{journal_only}); + } + + elsif ($type eq 'submissions') { + for (qw(tid section uid)) { + $terms{$_} = $processed{$_} if $processed{$_}; + } + %terms = (%terms, + note => $query->{note}, + ); + + $records = $oldsearch->findSubmission(\%terms, $start, $max, $sort); + } + + $self->prepResults($results, $records, [$total, $matches, $start, $max]); + return $results; +} + +################################################################# +# this is a way of adding extra search thingys; we could call another +# search method (as defaultSearch calls findRecords), or just make this our +# search method. +sub testSearch { + my($reader, $constants, $user, $form, $gSkin, $searchDB, $rss, $query, $opts) = @_; + + my $results = {}; + my $records = ['a' .. 'z']; + my $total = 26; + my $matches = 26; + my $start = $opts->{records_start} || 0; + my $max = $opts->{records_max} || 26; + + $records = [ @{$records}[$start .. ($start + $max)] ]; + $searchDB->prepResults($results, $records, [$total, $matches, $start, $max]); + + my %return; + $return{results} = $results; + $return{noresults} = 'No results'; + $return{template} = \ <[% letter %]

    +[% END %] +[% PROCESS pagination %] +

    +EOT + + $return{rss} = {} if $rss; + + return \%return; +} + +1; + +__END__ Index: slashjp/plugins/SearchToo/SearchToo/Indexer.pm diff -u /dev/null slashjp/plugins/SearchToo/SearchToo/Indexer.pm:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/SearchToo/Indexer.pm Wed Jul 12 20:41:57 2006 @@ -0,0 +1,407 @@ +package Slash::SearchToo::Indexer; + +use strict; +use File::Copy; +use File::Find; +use File::Path; +use File::Spec::Functions; +use Slash::Utility; +use Slash::DB::Utility; +use vars qw($VERSION); +use base 'Slash::SearchToo'; +use base 'Slash::SearchToo::Classic'; + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +# FRY: I did it! And it's all thanks to the books at my local library. + +# This is a superclass for various SearchToo engines that do indexing etc. + + +################################################################# +# fields that will be combined into the content field, +# for indexing and tokenization; first field is main one to excerpt +our %content = ( + comments => [qw(comment subject)], + stories => [qw(introtext bodytext title)], +); + +# additional fields that will be indexed and tokenized +our %text = ( + comments => [ qw(tids) ], + stories => [ qw(tids) ], +); + +our %primary = ( + comments => 'cid', +); + +# turn into hashes +for my $hash (\%text, \%content) { + for my $type (keys %$hash) { + my $arr = $hash->{$type}; + $hash->{$type} = { map { ($_ => 1) } @$arr }; + $hash->{_array}{$type} = $arr; + } +} + +################################################################# +sub new { + my($class, $user) = @_; + my $plugin = getCurrentStatic('plugin'); + return unless $plugin->{'SearchToo'}; + + my $handled; + { no strict; + $handled = ${$class . '::handled'}; + } + + my $self = { + _fields => { + content => \%content, + text => \%text, + primary => \%primary, + }, + }; + $self->{_handled} = $handled if $handled; + + bless $self, $class; + $self->{virtual_user} = $user; + $self->sqlConnect(); + + return $self; +} + +################################################################# +sub findRecords { + my($self, $type, $query, $opts) = @_; + + # let Classic handle for now + return Slash::SearchToo::Classic::findRecords(@_) unless $self->_handled($type); + +slashProfInit(); +slashProf('findRecords setup'); + + my $constants = getCurrentStatic(); + + my $processed = $self->_fudge_data($query); + my $results = {}; + my $records = []; + + ### set up common query terms + my $terms = { + query => $query->{query}, + }; + + + ### set up common options + my $sopts = {}; + $sopts->{total} = 0; + $sopts->{matches} = 0; + $sopts->{start} = $opts->{records_start} || 0; + $sopts->{max} = $opts->{records_max} || $constants->{search_default_display}; + + # sort can be an arrayref, but stick with one for now + ## no way to sort by date yet + $sopts->{sort} = ref $opts->{sort} ? $opts->{sort}[0] : $opts->{sort}; + $sopts->{sort} = ($opts->{sort} eq 'date' || $opts->{sort} eq 1) ? 1 : + ($opts->{sort} eq 'relevance' || $opts->{sort} eq 2) ? 2 : + 0; + + ### dispatch to different queries + if ($type eq 'comments') { + for (qw(section)) { + $terms->{$_} = $processed->{$_} if $processed->{$_}; + } + %$terms = (%$terms, + sid => $query->{sid}, + points_min => $query->{points_min}, + ); + } + +slashProf('_findRecords', 'findRecords setup'); + $self->_findRecords($results, $records, $sopts, $terms, $opts); +slashProf('getRecords', '_findRecords'); + $self->getRecords($type => $records); +slashProf('prepResults', 'getRecords'); + $self->prepResults($results, $records, $sopts); +slashProf('', 'getRecords'); + +slashProfEnd(); + + return $results; + + +} + +################################################################# +sub addRecords { + my($self, $type, $data, $opts) = @_; + + return unless $self->_handled($type); + +slashProfInit(); +slashProf('addRecords setup'); + + $data = [ $data ] unless ref $data eq 'ARRAY'; + + my @documents; + +slashProf('prepare records', 'addRecords setup'); + + for my $record (@$data) { + next unless keys %$record; + my $processed = $self->_fudge_data($record); + my %document; + + if ($type eq 'comments') { + %document = ( + cid => $record->{cid}, + + date => $record->{date}, + points => $record->{points}, + + comment => $record->{comment}, + subject => $record->{subject}, + sid => $record->{discussion_id}, + primaryskid => $processed->{section}, + tids => join(' ', @{$processed->{topic}}), + ); + } + + push @documents, \%document; + } + + # so we can index outside the main dir + if ($opts->{dir}) { + $self->_dir($opts->{dir}); + } + + # only bother if not adding, i.e., if modifying; if adding we + # assume it is new + unless ($opts->{add}) { + $self->deleteRecords($type => [ map $_->{ $self->{_fields}{primary}{$type} }, @documents ]); + } + +slashProf('add docs', 'prepare records'); + + my $count = $self->_addRecords($type, \@documents, $opts); + +slashProf('', 'add docs'); + + # clear it out when we're done + if ($opts->{dir}) { + $self->_dir(''); + } + +slashProfEnd(); + + return $count; +} + +################################################################# +sub prepRecord { + my($self, $type, $data, $opts) = @_; + + return unless $self->_handled($type); + + # default to writer + my $db = $opts->{db} || getCurrentDB(); + my %record; + + $data = { $primary{$type} => $data } unless ref $data; + + # this could possibly be done to get a bunch of comments at once ... + if ($type eq 'comments') { + my $comment = $db->getComment($data->{cid}) or return {}; + for (qw(date points cid subject)) { + $record{$_} = $comment->{$_}; + } + + $record{comment} = $data->{comment} || $db->getCommentText($data->{cid}); + + my $discussion = $db->getDiscussion($comment->{sid}); + $record{discussion_id} = $discussion->{id}; + $record{section} = $discussion->{primaryskid}; + $record{topic} = $discussion->{stoid} + ? $db->getStoryTopicsRendered($discussion->{stoid}) + : $discussion->{topic}; + } + + return \%record; +} + +################################################################# +sub getRecords { + my($self, $type, $data, $opts) = @_; + + return unless $self->_handled($type); + + # default to ... search? reader? + my $db = $opts->{db} || getObject('Slash::DB', { type => 'reader' }); + my %record; + + if ($type eq 'comments') { + for my $datum (@$data) { + # just return the whole comment ... why not? + my $comment = $db->getComment($datum->{cid}); + if ($comment) { + @{$datum}{keys %$comment} = values %$comment; + } else { + $datum = {}; + next; + } + if ($comment->{sid}) { + my $discussion = $db->getDiscussion($comment->{sid}); + @{$datum}{qw( + primaryskid url title + author_uid did + )} = @{$discussion}{qw( + primaryskid url title + uid id + )}; + } + } + } +} + +################################################################# +# handle delete too? +sub storeRecords { + my($self, $type, $data, $opts) = @_; +return; + return unless $self->_handled($type); + + my $slashdb = getCurrentDB(); + + $data = [ $data ] unless ref $data eq 'ARRAY'; + + my $count = 0; + for my $record (@$data) { + next unless $record; + + # deal with multiple instances of same type => id + $count++ if $slashdb->sqlInsert('search_index_dump', { + type => $type, + id => $record, + status => $opts->{add} ? 'new' : 'changed', + }); + } + + return $count; +} + +################################################################# +# move prepared index data to live +sub moveLive { + my($self, $type, $dir) = @_; + + return unless $self->can('_dir') && ($dir || $self->can('_backup_dir')); + + my $backup_dir = $self->_backup_dir($type, $dir); + $dir = $self->_dir($type, ''); + + my @time = localtime; + my $now = sprintf "-%04d%02d%02d-%02d%02d%02d", $time[5]+1900, $time[4]+1, $time[3], $time[2], $time[1], $time[0]; + $dir =~ s|/+$||; # just in case + my $olddir = $dir . $now; + my $tmpdir = $dir . '-tmp'; + + # copy staging to temp dir + _moveFind($backup_dir, $tmpdir); + # move live to backup + rename($dir, $olddir); + # move temp to live + rename($tmpdir, $dir); + + # kick old? +} + +################################################################# +sub _moveFind { + my($olddir, $newdir); + find(sub { + my($old) = $File::Find::name; + my $new = s/^\Q$olddir/$newdir/; + if (-d $old) { + eval { + mkpath($new, 0, 0775); + }; + if ($@) { + warn "Can't create path $new: $@"; + } + } elsif (-f _) { + copy($old, $new) or warn "Can't copy file $new: $!"; + } + }, $olddir); +} + +################################################################# +sub _field_exists { + my($self, $field, $key, $type) = @_; + return unless $field; + $type = $self->_type($type); + + return $self->{_fields}{$field}{$type}{$key}; +} + +################################################################# +sub _field_list { + my($self, $field, $type) = @_; + return unless $field; + $type = $self->_type($type); + + return $self->{_fields}{$field}{_array}{$type}; +} + +################################################################# +sub _primary { + my($self, $type) = @_; + $type = $self->_type($type); + + return $self->{_fields}{primary}{$type}; +} + +################################################################# +sub _handled { + my($self, $type) = @_; + $type = $self->_type($type); + return $type =~ $self->{_handled}; +} + +################################################################# +sub _type { + my($self, $type) = @_; + $self->{_type} = $type if defined $type; + return $self->{_type}; +} + +################################################################# +sub _class { + my($self) = @_; + unless ($self->{_class}) { + ($self->{_class} = lc ref $self) =~ s/^.+:://; + } + return $self->{_class}; +} + +################################################################# +sub _dir { + my($self, $type, $dir) = @_; + $self->{_dir} = $dir if defined $dir; + $self->{_dir} ||= catdir(getCurrentStatic('datadir'), 'search_index'); + + return catdir($self->{_dir}, $self->_class, $self->_type($type)); +} + +################################################################# +sub _backup_dir { + my($self, $type, $dir) = @_; + my $backup_dir = $dir || catdir(getCurrentStatic('datadir', 'search_index_tmp')); + + return $self->_dir($type, $backup_dir); +} + +1; + +__END__ Index: slashjp/plugins/SearchToo/SearchToo/Kinosearch.pm diff -u /dev/null slashjp/plugins/SearchToo/SearchToo/Kinosearch.pm:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/SearchToo/Kinosearch.pm Wed Jul 12 20:41:57 2006 @@ -0,0 +1,330 @@ +package Slash::SearchToo::Kinosearch; + +# STILL IN PROGRESS NOT READY FOR USE + +use strict; +use File::Path; +use File::Spec::Functions; +use Slash::Utility; +use Slash::DB::Utility; +use vars qw($VERSION); +use base 'Slash::SearchToo::Indexer'; + +use Search::Kinosearch::KSearch; +use Search::Kinosearch::Kindexer; + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +# FRY: I did it! And it's all thanks to the books at my local library. + +our $handled = qr{^(?:comments)$}; + +our $backend = 'DB_File'; + +################################################################# +sub getOps { + my %ops = ( + stories => 1, + comments => 1, + journals => 1, + polls => 1, + users => 1, + submissions => 1, + ); + return \%ops; +} + +################################################################# +sub _findRecords { + my($self, $results, $records, $sopts, $terms, $opts) = @_; + + my $constants = getCurrentStatic(); + +slashProf('init search'); + + my $querystring = $terms->{query}; + # escape special chars + # none, allow all special chars +# $querystring =~ s/([&^|!{}[\]:\\])~*?/\\$1/g; # allowed: ()"+- + # normalize to lower case ??? + $querystring =~ s/\b(?!AND|NOT|OR)(\w+)\b/\L$1/g; + + $sopts->{max}++; # until we get matches/num_hits working + my $searcher_opts = { + -num_results => $sopts->{max}, + -offset => $sopts->{start}, + -excerpt_field => $self->_field_list('content')->[0] + }; + + if ($sopts->{'sort'} == 1) { + $searcher_opts->{-sort_by} = 'timestamp'; + } elsif ($sopts->{'sort'} == 2) { + $searcher_opts->{-sort_by} = 'relevance'; + } + + my $searcher = $self->_searcher(undef, undef, $searcher_opts) or return $results; + + $searcher->add_query( + -string => $querystring, + -lowercase => 1, + -tokenize => 1, + -stem => 1, + -required => 1, + -fields => { # ??? adjust weights? + map { ( $_ => 1 ) } $self->_field_list('content') + } + ); + + +# if (length $terms->{points_min}) { # ??? +# # no need to bother with adding this to the query, since it's all comments +# if ($terms->{points_min} == $constants->{comment_minscore}) { +# delete $terms->{points_min}; +# } else { # ($terms{points_min} != $constants->{comment_maxscore}) { + delete $terms->{points_min}; +# } +# } + + for my $key (keys %$terms) { + next if $key eq 'query' || ! length($terms->{$key}); + + $searcher->add_query( + -string => $terms->{$key}, + -required => 1, + -fields => $key, + ); + } + +#use Data::Dumper; +#print Dumper $searcher; + +slashProf('search', 'init search'); + my $status = $searcher->process || {}; + + $sopts->{total} = $status->{num_docs}; + $sopts->{matches} = $status->{num_hits}; + +slashProf('fetch results', 'search'); + + while (my $obj = $searcher->fetch_result_hashref) { + my %data = ( + score => $obj->{score}, + $self->_primary => $obj->{doc_id}, + excerpt => $obj->{excerpt}, + ); + + push @$records, \%data; + } + +slashProf('', 'fetch results'); + +use Data::Dumper; +print Dumper $records; + + return 1; +} + +################################################################# +sub _addRecords { + my($self, $type, $documents, $opts) = @_; + + my $writer = $opts->{writer} || $self->_writer; + + if (!$writer->{_is_old}) { # ??? + for my $field (keys %{$documents->[0]}) { + $writer->define_field( + -name => $field, + # only store the main content field, for excerpting + -store => $self->_field_list('content')->[0] eq $field + ); + } + } + + my $count = 0; + my @docs; + for my $document (@$documents) { + my %doc; + # start new document by *id + $writer->new_document($document->{ $self->_primary }); + +#printf "%d:%s\n", $document->{ $self->_primary }, $document->{date}; + + # timestamp is Unix epoch + if ($document->{date}) { + $writer->set_document_timestamp(timeCalc(delete $document->{date}, "%s", 0)); + } + + for my $key (keys %$document) { + next unless length $document->{$key}; + next if $key eq $self->_primary; + + $writer->set_field($key => $document->{$key}); + + my $is_text = $self->_field_exists(text => $key); + my $is_content = $self->_field_exists(content => $key); + + if ($is_text || $is_content) { + $writer->lc_field($key) if $is_content; + $writer->tokenize_field($key); + $writer->stem_field($key) if $is_content; + } +#printf "%s:%s\n", $key, $document->{$key}; + } + + $writer->add_document; +#printf "%d\n\n", $count; + $count++; + } + + $writer->finish unless $opts->{writer}; + +# # only optimize if requested (as usual), and changes were made +# $self->optimize($type) if $opts->{optimize} && $count; + + return $count; +} + +################################################################# +# Plucene-specific helper methods +sub isIndexed { # ??? + my($self, $type, $id, $opts) = @_; + + return unless $self->_handled($type); + + my $preader = ($opts->{_reader} || $self->_reader) or return; + + my $found = $preader->doc_is_indexed($id); + +# $preader->close unless $opts->{_reader}; + + return $found || 0; +} + +################################################################# +sub optimize { # ??? + my($self, $type) = @_; + + return unless $self->_handled($type); + +slashProf('optimize'); + +slashProf('', 'optimize'); + + return 1; +} + +################################################################# +sub merge { # ??? + my($self, $type, $dirs, $opts) = @_; + + return unless $self->_handled($type); + +slashProf('merge'); + + my @alldirs; + for (@$dirs) { + push @alldirs, $self->_dir($type => $_); + } + my $dir = $self->_dir($type => $opts->{dir}); + ## backup $dir? + +slashProf('', 'merge'); + + return scalar @alldirs; +} + +################################################################# +sub deleteRecords { # ??? + my($self, $type, $ids, $opts) = @_; + + return unless $self->_handled($type); + +slashProf('deleteRecords'); + + my $preader = $self->_reader or return; + + $ids = [ $ids ] unless ref $ids; + + my $count = 0; + for my $id (@$ids) { + my($found) = $self->isIndexed($type => $id, { _reader => $preader }); + if ($found) { + $count += $found; + $preader->delete_document($id); + } + } + +# # only optimize if requested (as usual), and changes were made +# $self->optimize($type) if $opts->{optimize} && $count; + +slashProf('', 'deleteRecords'); + + return $count; +} + +################################################################# +sub _searcher { + my($self, $type, $dir, $opts) = @_; + $dir = $self->_dir($type, $dir); + + my $constants = getCurrentStatic(); + $opts ||= {}; + + my $preader = $self->_reader($type) or return undef; + + return Search::Kinosearch::KSearch->new( + -stoplist => {}, + -kindex => $preader, + -any_or_all => 'all', + -sort_by => 'relevance', # relevance, timestamp + -allow_boolean => 0, + -allow_phrases => 0, +# -max_terms => 6, # ??? + -excerpt_length => $constants->{search_text_length}, + %$opts + ); +} + +################################################################# +sub _reader { + my($self, $type, $dir) = @_; + $dir = $self->_dir($type, $dir); + + return undef unless -e catdir($dir, 'kindex'); + + return Search::Kinosearch::Kindexer->new( + -stoplist => {}, + -mode => 'readonly', + -backend => $backend, + -kindexpath => catdir($dir, 'kindex'), + -kinodatapath => catdir($dir, 'kindex', 'kinodata'), + ); +} + +################################################################# +sub _writer { + my($self, $type, $dir) = @_; + $dir = $self->_dir($type, $dir); + + my $mode = -e catdir($dir, 'kindex') ? 'overwrite' : 'create'; + + my $tmp = catdir($dir, 'ktemp'); + + mkpath($dir, 0, 0775) unless -e $dir; + mkpath($tmp, 0, 0775) unless -e $tmp; + + return Search::Kinosearch::Kindexer->new( + -stoplist => {}, + -mode => $mode, # create, overwrite, update, readonly + -backend => $backend, + -kindexpath => catdir($dir, 'kindex'), + -kinodatapath => catdir($dir, 'kindex', 'kinodata'), + -temp_directory => catdir($dir, 'ktemp'), + -enable_updates => 0, + -phrase_matching => 0, + ); +} + +1; + +__END__ Index: slashjp/plugins/SearchToo/SearchToo/Makefile.PL diff -u /dev/null slashjp/plugins/SearchToo/SearchToo/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/SearchToo/Makefile.PL Wed Jul 12 20:41:57 2006 @@ -0,0 +1,11 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'PM' => { + 'Classic.pm' => '$(INST_LIBDIR)/Slash/SearchToo/Classic.pm', + 'Indexer.pm' => '$(INST_LIBDIR)/Slash/SearchToo/Indexer.pm', + 'Kinosearch.pm' => '$(INST_LIBDIR)/Slash/SearchToo/Kinosearch.pm', + 'Plucene.pm' => '$(INST_LIBDIR)/Slash/SearchToo/Plucene.pm', + }, +); Index: slashjp/plugins/SearchToo/SearchToo/Plucene.pm diff -u /dev/null slashjp/plugins/SearchToo/SearchToo/Plucene.pm:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/SearchToo/Plucene.pm Wed Jul 12 20:41:57 2006 @@ -0,0 +1,385 @@ +package Slash::SearchToo::Plucene; + +# STILL IN PROGRESS NOT READY FOR USE + +use strict; +use File::Spec::Functions; +use Slash::Utility; +use Slash::DB::Utility; +use Slash::SearchToo::Classic; +use vars qw($VERSION); +use base 'Slash::SearchToo::Indexer'; + +use Plucene::Document; +use Plucene::Document::DateSerializer; +use Plucene::Index::Writer; +use Plucene::QueryParser; +use Plucene::Search::HitCollector; +use Plucene::Search::IndexSearcher; +use Plucene::Search::TermQuery; + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +# FRY: I did it! And it's all thanks to the books at my local library. + +our $handled = qr{^(?:comments)$}; + +################################################################# +sub getOps { + my %ops = ( + stories => 1, + comments => 1, + journals => 1, + polls => 1, + users => 1, + submissions => 1, + ); + return \%ops; +} + +################################################################# +sub _findRecords { + my($self, $results, $records, $sopts, $terms, $opts) = @_; + + my $constants = getCurrentStatic(); + +slashProf('init search', 'findRecords setup'); + + my $parser = Plucene::QueryParser->new({ + analyzer => $self->_analyzer, + default => 'content' + }); + + my $querystring = $terms->{query}; + # escape special chars + $querystring =~ s/([-+&|!{}[\]:\\])~*?/\\$1/g; # allowed: ()"^ + # normalize to lower case + $querystring =~ s/\b(?!AND|NOT|OR)(\w+)\b/\L$1/g; + my $newquery; + eval { $newquery = $parser->parse('+(' . $querystring . ')') } or return $results; + + my $filter = 0; + if (length $terms->{points_min}) { + # no need to bother with adding this to the query, since it's all comments + if ($terms->{points_min} == $constants->{comment_minscore}) { + delete $terms->{points_min}; + } else { # ($terms{points_min} != $constants->{comment_maxscore}) { + $filter = Slash::SearchToo::Plucene::Filter->new({ + field => '_points_', + from => _get_sortable_points(delete $terms->{points_min}), + to => _get_sortable_points($constants->{comment_maxscore}), + }); + } + } + + for my $key (keys %$terms) { + next if $key eq 'query' || ! length($terms->{$key}); + my $term = Plucene::Index::Term->new({ + field => $key, + text => $terms->{$key} + }) or next; + my $term_query = Plucene::Search::TermQuery->new({ term => $term }) or next; + $newquery->add($term_query, 1); + } +#use Data::Dumper; +#print STDERR Dumper $newquery; +#print STDERR $newquery->to_string, ":$filter\n"; + + my $searcher = $self->_searcher or return $results; +slashProf('search', 'init search'); + my $docs = $searcher->search_top($newquery, $filter, $sopts->{start} + $sopts->{max}); + + $sopts->{total} = $searcher->max_doc; + $sopts->{matches} = $docs->total_hits; + +slashProf('fetch results', 'search'); + my $skip = $sopts->{start}; + for my $obj (sort { $b->{score} <=> $a->{score} } $docs->score_docs) { + if ($skip > 0) { + $skip--; + next; + } + + last if @$records >= $sopts->{max}; + + my($doc, $score) = @{$obj}{qw(doc score)}; + my $docobj = $searcher->doc($doc); + my %data = ( score => $score ); + + for my $field ($docobj->fields) { + my $name = $field->name; + next if $name =~ /^(?:content|id)$/; + $data{$name} = $field->string; + } + + push @$records, \%data; + } + + return 1; +} + +################################################################# +sub _addRecords { + my($self, $type, $documents, $opts) = @_; + + my $writer = $self->_writer; + + my $count = 0; + for my $document (@$documents) { + my $doc = Plucene::Document->new; + + # combine our text fields into one, and then remove them; we + # don't need them stored separately + # normalize to lower case + $document->{content} = lc join ' ', @{$document}{ @{$self->_field_list('content')} }; + delete @{$document}{ @{$self->_field_list('content')} }; + + $document->{_date_} = _get_sortable_date(delete $document->{date}); + $document->{_points_} = _get_sortable_points(delete $document->{points}); + + for my $key (keys %$document) { + next unless length $document->{$key}; + my $field; + + if ($key eq 'content' || $self->_field_exists(text => $key)) { + $field = Plucene::Document::Field->Text($key, $document->{$key}); + } else { + $field = Plucene::Document::Field->Keyword($key, $document->{$key}); + } + + $doc->add($field); + } + + $writer->add_document($doc); + $count++; + } + + undef $writer; + + # only optimize if requested (as usual), and changes were made + $self->optimize($type) if $opts->{optimize} && $count; + + return $count; + +} + +################################################################# +# Plucene-specific helper methods +sub isIndexed { + my($self, $type, $id, $opts) = @_; + + return unless $self->_handled($type); + + my $preader = ($opts->{_reader} || $self->_reader) or return; + + my $term = Plucene::Index::Term->new({ + field => $self->_primary, + text => $id + }); + + my $found = $preader->doc_freq($term); + + $preader->close unless $opts->{_reader}; + + return $found ? ($found, $term) : 0; +} + +################################################################# +sub optimize { + my($self, $type) = @_; + + return unless $self->_handled($type); + +slashProf('optimize'); + + my $writer = $self->_writer; + $writer->optimize; + undef $writer; +slashProf('', 'optimize'); + + return 1; +} + +################################################################# +sub merge { + my($self, $type, $dirs, $opts) = @_; + + return unless $self->_handled($type); + +slashProf('merge'); + + my @alldirs; + for (@$dirs) { + push @alldirs, $self->_dir($type => $_); + } + my $dir = $self->_dir($type => $opts->{dir}); + ## backup $dir? + + if (@alldirs) { + my $writer = $self->_writer; + $writer->add_indexes(@alldirs); + } + +slashProf('', 'merge'); + + return scalar @alldirs; +} + +################################################################# +sub deleteRecords { + my($self, $type, $ids, $opts) = @_; + + return unless $self->_handled($type); + +slashProf('deleteRecords'); + + my $preader = $self->_reader or return; + + $ids = [ $ids ] unless ref $ids; + + my $count = 0; + for my $id (@$ids) { + my($found, $term) = $self->isIndexed($type => $id, { _reader => $preader }); + if ($found) { + $count += $found; + $preader->delete_term($term); + } + } + + $preader->close; + + # only optimize if requested (as usual), and changes were made + $self->optimize($type) if $opts->{optimize} && $count; + +slashProf('', 'deleteRecords'); + + return $count; +} + +################################################################# +# make it easier to sort by serializing the date +sub _get_sortable_date { + my($time, $format) = @_; + $format ||= '%Y-%m-%d %H:%M:%S'; + return freeze_date(Time::Piece->strptime($time, $format)); +} + +################################################################# +# make it easier to sort by converting to alphabet +sub _get_sortable_points { + my($points) = @_; + + my $constants = getCurrentStatic(); + my $min = $constants->{comment_minscore}; + my $max = $constants->{comment_maxscore}; + + $points = $points < $min + ? $min + : $points > $max + ? $max + : $points; + + my $start = $min; + my $finish = 'a'; + until ($start == $points) { + $start++; + $finish++; + } + + return $finish; +} + +################################################################# +sub _searcher { + my($self, $type, $dir) = @_; + $type = $self->_type($type); + $dir = $self->_dir($type, $dir); + + return $self->{_searcher}{$type}{$dir} if $self->{_searcher}{$type}{$dir}; + + return -e $dir + ? ($self->{_searcher}{$type}{$dir} = Plucene::Search::IndexSearcher->new($dir)) + : undef; +} + +################################################################# +sub _reader { + my($self, $type, $dir) = @_; + $type = $self->_type($type); + $dir = $self->_dir($type, $dir); + + return $self->{_reader}{$type}{$dir} if $self->{_reader}{$type}{$dir}; + + return -e $dir + ? ($self->{_reader}{$type}{$dir} = Plucene::Index::Reader->open($dir)) + : undef; +} + +################################################################# +sub _writer { + my($self, $type, $dir) = @_; + $type = $self->_type($type); + $dir = $self->_dir($type, $dir); + + return $self->{_writer}{$type}{$dir} if $self->{_writer}{$type}{$dir}; + + return $self->{_writer}{$type}{$dir} = Plucene::Index::Writer->new( + $dir, $self->_analyzer, + -e catfile($dir, 'segments') ? 0 : 1 + ); +} + +################################################################# +sub close_searcher { + my($self, $type, $dir) = @_; + $type = $self->_type($type); + $dir = $self->_dir($type, $dir); + + my $searcher = delete $self->{_searcher}{$type}{$dir} or return; + $searcher->close; +} + +################################################################# +sub close_reader { + my($self, $type, $dir) = @_; + $type = $self->_type($type); + $dir = $self->_dir($type, $dir); + + my $preader = delete $self->{_reader}{$type}{$dir} or return; + $preader->close; +} + +################################################################# +sub close_writer { + my($self, $type, $dir) = @_; + $type = $self->_type($type); + $dir = $self->_dir($type, $dir); + + my $writer = delete $self->{_writer}{$type}{$dir} or return; + undef $writer; +} + +# maybe add our own analyzer ... +use Plucene::Analysis::StopAnalyzer; +sub _analyzer { + return Plucene::Analysis::StopAnalyzer->new; +} + +################################################################# +################################################################# +package Slash::SearchToo::Plucene::Filter; +use base 'Plucene::Search::DateFilter'; + +sub new { + my($self, $args) = @_; + bless { + field => $args->{field}, + from => $args->{from}, + to => $args->{to}, + }, $self; +} + + +1; + +__END__ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:57 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:57 +0900 Subject: [Slashdotjp-dev 480] CVS update: slashjp/plugins/SearchToo Message-ID: <20060712114157.94F442AC00E@users.sourceforge.jp> Index: slashjp/plugins/SearchToo/MANIFEST diff -u /dev/null slashjp/plugins/SearchToo/MANIFEST:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/MANIFEST Wed Jul 12 20:41:57 2006 @@ -0,0 +1,19 @@ +MANIFEST +Makefile.PL +PLUGIN +SearchToo/Classic.pm +SearchToo/Makefile.PL +SearchToo.pm +dump +searchtoo.pl +templates/commentsearch;searchtoo;default +templates/data;searchtoo;default +templates/journalsearch;searchtoo;default +templates/nosearch;searchtoo;default +templates/pagination;searchtoo;default +templates/pollsearch;searchtoo;default +templates/searchform;searchtoo;default +templates/searchrss;searchtoo;default +templates/storysearch;searchtoo;default +templates/subsearch;searchtoo;default +templates/usersearch;searchtoo;default Index: slashjp/plugins/SearchToo/Makefile.PL diff -u /dev/null slashjp/plugins/SearchToo/Makefile.PL:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/Makefile.PL Wed Jul 12 20:41:57 2006 @@ -0,0 +1,10 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'Slash::SearchToo', + 'VERSION_FROM' => 'SearchToo.pm', # finds $VERSION + 'PM' => { + 'SearchToo.pm' => '$(INST_LIBDIR)/SearchToo.pm', + }, +); Index: slashjp/plugins/SearchToo/PLUGIN diff -u /dev/null slashjp/plugins/SearchToo/PLUGIN:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/PLUGIN Wed Jul 12 20:41:57 2006 @@ -0,0 +1,17 @@ +# $Id: PLUGIN,v 1.1 2006/07/12 11:41:57 sugi Exp $ +name=SearchToo +htdoc=searchtoo.pl +mysql_dump=dump +description="SearchToo is the frontend search API for Slash" +requiresplugin=Search +template=templates/commentsearch;searchtoo;default +template=templates/data;searchtoo;default +template=templates/journalsearch;searchtoo;default +template=templates/nosearch;searchtoo;default +template=templates/pagination;searchtoo;default +template=templates/pollsearch;searchtoo;default +template=templates/searchform;searchtoo;default +template=templates/searchrss;searchtoo;default +template=templates/storysearch;searchtoo;default +template=templates/subsearch;searchtoo;default +template=templates/usersearch;searchtoo;default Index: slashjp/plugins/SearchToo/SearchToo.pm diff -u /dev/null slashjp/plugins/SearchToo/SearchToo.pm:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/SearchToo.pm Wed Jul 12 20:41:57 2006 @@ -0,0 +1,136 @@ +package Slash::SearchToo; + +use strict; +use Slash::Utility; +use Slash::DB::Utility; +use vars qw($VERSION); +use base 'Slash::DB::Utility'; + +($VERSION) = ' $Revision: 1.1 $ ' =~ /\$Revision:\s+([^\s]+)/; + +# FRY: Prepare to be thought at! + +################################################################# +sub new { + my($class, $user, @args) = @_; + + my $constants = getCurrentStatic(); + return unless $constants->{plugin}{'SearchToo'}; + + my $api_class = $constants->{search_too_class} || 'Slash::SearchToo::Classic'; + # we COULD do a use base here ... but then different Slash sites + # cannot use different backends, so hang it -- pudge + my $self = getObject($api_class, $user, @args); + + if (!$self) { + warn "Could not get $api_class"; + $self = {}; + bless($self, $class); + $self->{virtual_user} = $user; + $self->sqlConnect(); + } + + return $self; +} + +################################################################# +# these may be implemeted in backend modules +sub getOps { + my %ops = ( + comments => 1, + stories => 1, + ); + return \%ops; +} + +################################################################# +# these are implemeted only in backend modules +sub findRecords { warn "findRecords must be implemented in a subclass"; return } +# these are OK to be nonfunctional +sub storeRecords { return } +sub addRecords { return } +sub prepRecord { return } +sub getRecords { return } + + +################################################################# +# take the results and prepare the data for returning +sub prepResults { + my($self, $results, $records, $sopts) = @_; + + # two ways of calling + if (ref $sopts eq 'ARRAY') { + $sopts = { + total => $sopts->[0], + matches => $sopts->[1], + start => $sopts->[2], + max => $sopts->[3] + }; + } + + ### prepare results + $records ||= []; + $results->{records_next} = 0; + $results->{records_end} = scalar @$records + ? ($sopts->{start} + @$records - 1) + : undef; + + if (defined $sopts->{matches}) { + $results->{records_next} = $results->{records_end} + 1 + if $sopts->{matches} > $results->{records_end} + 1; + } else { + # we added one before; subtract it now + --$sopts->{max}; + if (@$records >= $sopts->{max}) { + pop @$records; + $results->{records_next} = $sopts->{start} + $sopts->{max}; + $results->{records_end} = $results->{records_next} - 1; + } + } + + $results->{records} = $records; + $results->{records_returned} = scalar @$records; + $results->{records_total} = $sopts->{total}; + $results->{records_matches} = $sopts->{matches}; + $results->{records_max} = $sopts->{max}; + $results->{records_start} = $sopts->{start}; + + return $results; +} + + +################################################################# +# basic processing for common data types +sub _fudge_data { + my($self, $data) = @_; + + my %processed; + + if ($data->{topic}) { + my @topics = ref $data->{topic} + ? @{$data->{topic}} + : $data->{topic}; + $processed{topic} = \@topics; + } else { + $processed{topic} = []; + } + + if ($data->{section}) { + # make sure we pass a skid + if ($data->{section} =~ /^\d+$/) { + $processed{section} = $data->{section}; + } else { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + # get section name, for most compatibility with this API + my $skid = $reader->getSkidFromName($data->{section}); + $processed{section} = $skid if $skid; + } + } + + return \%processed; +} + + +1; + +__END__ Index: slashjp/plugins/SearchToo/dump diff -u /dev/null slashjp/plugins/SearchToo/dump:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/dump Wed Jul 12 20:41:57 2006 @@ -0,0 +1,18 @@ +# +# $Id: dump,v 1.1 2006/07/12 11:41:57 sugi Exp $ +# + +INSERT INTO vars (name, value, description) VALUES ('search_too_class', 'Slash::SearchToo::Classic', 'Default backend search API class'); + + +## these are all from the Search plugin + +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_default_display', '30', 'Default number of entries to display on Search page'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_journal_enabled', '1', 'Turns on searching journals.'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_rss_enabled', '1', 'Turns on searching rss.'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_method', '', 'Method to use to weight scores for search returns (and to narrow down possible matches)'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_text_length','80','This will tell search how many characters should be returned for text bodies in searches (think introtext for stories and article for journals).'); + +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_rdfitemdesc','0','1 == include introtext in item description; 0 == don\'t. Any other number is substr() of introtext to use'); +INSERT IGNORE INTO vars (name, value, description) VALUES ('search_rdfitemdesc_html','0','1 == include HTML in item description; 0 == strip HTML (plain text only)'); + Index: slashjp/plugins/SearchToo/searchtoo.pl diff -u /dev/null slashjp/plugins/SearchToo/searchtoo.pl:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/searchtoo.pl Wed Jul 12 20:41:57 2006 @@ -0,0 +1,196 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: searchtoo.pl,v 1.1 2006/07/12 11:41:57 sugi Exp $ + +use strict; +use Slash; +use Slash::Display; +use Slash::Utility; +use Slash::XML; + +################################################################# +sub main { + my $reader = getObject('Slash::DB', { db_type => 'reader' }); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $gSkin = getCurrentSkin(); + my $searchDB = getObject('Slash::SearchToo', { db_type => 'search' }); + + my $ops = $searchDB->getOps; + + # Backwards compatibility, we now favor tid over topic + if ($form->{topic}) { + if ($form->{topic} =~ s/^([+-]?[\d.]+).*$/$1/s) { + $form->{tid} ||= $form->{topic}; + } + delete $form->{topic}; + } + + # for now, so they can coexist, this search is called "searchtoo" ... + # we will probably keep this as "searchtoo" even when we change the + # page name back to "search.pl", just so we can keep it separate + $user->{currentPage} = 'searchtoo'; + + # Set some defaults + $form->{query} ||= ''; + $form->{'sort'} ||= 1; # 'date'; + $form->{threshold} = $user->{threshold} unless defined $form->{threshold}; + $form->{op} = 'stories' if !$form->{op} || !exists $ops->{$form->{op}}; + + # switch search mode to poll if in polls skin and other + # search type isn't specified + if ($gSkin->{name} eq 'polls' && !$form->{op}) { + $form->{op} = 'polls'; + $form->{section} = ''; + + # submissions only available to regular users if proper constant set + } elsif ($form->{op} eq 'submissions' && !$user->{is_admin}) { + $form->{op} = 'stories' unless $constants->{submiss_view}; + } + + my $rss = $form->{content_type} =~ $constants->{feed_types} && $constants->{search_rss_enabled}; + + my $querystring = strip_notags($form->{query}); + my $header_title = getData('search_header_title', { text => $querystring }); + my $titlebar_title = getData('search_titlebar_title', { text => $querystring }); + + # Here, panic mode is handled without needing to call the + # individual search subroutines; we're going to tell the + # user the same thing in each case anyway. + if ($constants->{panic} >= 1 || $constants->{search_google} || !$searchDB) { + header($header_title) or return; + titlebar('100%', $titlebar_title); + slashDisplay('nosearch'); + footer(); + + # this is the bulk of it, where the MAGIC happens! + } elsif ($ops->{$form->{op}}) { + my %query; + $query{points_min} = $form->{threshold} if defined $form->{threshold}; + for (qw[query author op section journal_only submitter uid]) { + $query{$_} = $form->{$_} if defined $form->{$_}; + } + + my $topics = $form->{_multi}{tid} || $form->{tid}; + $query{topic} = $topics; + + my %opts = ( + # we accept any value for sort, + # and deal with filtering in the API + sort => $form->{sort}, + records_start => $form->{start}, + # XXX for now, don't let user define + # records_max => $form->{max}, + # XXX not yet used + date_start => '', + date_end => '', + ); + + $ops->{$form->{op}} = \&defaultSearch unless ref $ops->{$form->{op}} eq 'CODE'; + + my $return = $ops->{$form->{op}}->( + $reader, $constants, $user, $form, + $gSkin, $searchDB, $rss, \%query, \%opts + ); + + my $args = _buildargs({ + (map { $_ => $opts{$_} } + qw(sort date_start date_end)), + %query, + }); + + if ($rss) { + slashDisplay('searchrss', { + op => $form->{op}, + rss => $return->{rss}, + results => $return->{results}, + }, { Return => 0, Nocomm => 1 }); + + if (@{$return->{rss}{items}}) { + xmlDisplay($form->{content_type} => $return->{rss}); + } else { + # we redirect here, because we might not know + # if the op can do RSS until we get the result + redirect("$constants->{rootdir}$ENV{SCRIPT_NAME}?start=$opts{records_start}&$args"); + return; + } + + } else { + # XXX add RSS linkrel here ? ... + header($header_title) or return; + titlebar('100%', $titlebar_title); + + slashDisplay('searchform', { op => $form->{op} }); + + if (! @{$return->{results}{records}}) { + print $return->{noresults}; + } else { + slashDisplay($return->{template}, { + shorten => \&_shorten, + results => $return->{results}, + query => \%query, + args => $args, + }); + } + + footer(); + } + } + + my $keys = join '|', keys %$ops; + writeLog($form->{query}) if $form->{op} =~ /^(?:$keys)$/; +} + +################################################################# +sub defaultSearch { + my($reader, $constants, $user, $form, $gSkin, $searchDB, $rss, $query, $opts) = @_; + + my %return; + $return{results} = $searchDB->findRecords($form->{op} => $query, $opts); + + (my $singular_name = $form->{op}) =~ s/([^s])s$/$1/; + $singular_name = 'story' if $singular_name eq 'storie'; + $singular_name = 'sub' if $singular_name eq 'submission'; + + $return{template} = $singular_name . 'search'; + $return{noresults} = getData('no' . $form->{op}); + + $return{rss} = {} if $rss; # populate via searchrss template + + return \%return; +} + +################################################################# +sub _buildargs { + my($query) = @_; + my $uri; + + for (keys %$query) { + my $x = ""; + $x = $query->{$_} if defined $query->{$_} && $x eq ""; + $x =~ s/ /+/g; + $uri .= "$_=$x&" unless $x eq ""; + } + $uri =~ s/&$//; + + return fixurl($uri); +} + +################################################################# +sub _shorten { + my($text, $length) = @_; + $length ||= getCurrentStatic('search_text_length'); + return $text if length($text) <= $length; + $text = chopEntity($text, $length); + $text =~ s/(.*) .*$/$1.../g; + return $text; +} + +################################################################# +createEnvironment(); +main(); + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:57 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:57 +0900 Subject: [Slashdotjp-dev 481] CVS update: slashjp/plugins/SearchToo/templates Message-ID: <20060712114158.007A42AC00E@users.sourceforge.jp> Index: slashjp/plugins/SearchToo/templates/commentsearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/commentsearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/commentsearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,38 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +commentsearch +__template__ +[% IF constants.search_too_class == 'Slash::SearchToo::Classic' %] +

    This search covers only subjects of comments that are posted.

    +[% END %] + +[% FOREACH comment=results.records %] + [% user_email = Slash.db.getUser(comment.uid, ['fakeemail', 'nickname']) %] + [% comment.subject %] + + by [% user_email.nickname | strip_literal %] on [% Slash.timeCalc(comment.date) %]
    + + Attached to: [% comment.title %] posted on [% Slash.timeCalc(comment.ts) %]
    + [% IF comment.score %] + Score: [% comment.score %]
    + [% END %] + +

    +[% END %] +[% PROCESS pagination %] +

    + + +__seclev__ +100 +__version__ +$Id: commentsearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/data;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/data;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/data;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,83 @@ +__section__ +default +__description__ +Repository for random data elements. + +* value = the name of the data element to retrieve + +Each data element may have any number of other variables. +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +data +__template__ +[% SWITCH value %] + +[% CASE 'nousers' %] + [% returnme.data_constant = 1 %] + No usernames were found that match your query. + +[% CASE 'nostories' %] + [% returnme.data_constant = 1 %] + No stories were found that match your query. + +[% CASE 'nocomments' %] + [% returnme.data_constant = 1 %] + No comments were found that match your query. + +[% CASE 'nopolls' %] + [% returnme.data_constant = 1 %] + No poll questions were found that match your query. + +[% CASE 'nojournals' %] + [% returnme.data_constant = 1 %] + No journals were found to match your query. + +[% CASE 'nosubmissions' %] + [% returnme.data_constant = 1 %] + No submissions were found to match your query. + +[% CASE 'norss' %] + [% returnme.data_constant = 1 %] + No rss entries were found to match your query. + +[% CASE 'all_sections' %] + [% returnme.data_constant = 1 %] + All Sections + +[% CASE 'all_topics' %] + [% returnme.data_constant = 1 %] + All Topics + +[% CASE 'all_authors' %] + [% returnme.data_constant = 1 %] + All Authors + +[% CASE 'all_subsections' %] + [% returnme.data_constant = 1 %] + All Subsections + +[% CASE 'search_titlebar_title' %] + [% IF text.length > 0 %] + Searching For: [% text %] + [% ELSE %] + Search [% constants.sitename %] + [% END %] + +[% CASE 'search_header_title' %] + [% IF text.length > 0 %] + Search '[% text %]' + [% ELSE %] + Search [% constants.sitename %] + [% END %] + +[% END %] + +__seclev__ +10000 +__version__ +$Id: data;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/journalsearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/journalsearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/journalsearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,32 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +journalsearch +__template__ +[% FOREACH journal=results.records %] + [% journal.description %]
    + On [% Slash.timeCalc(journal.date) %]
    + [% shorten( Slash.strip_notags(journal.article) ) %]
    + + Author: [% journal.nickname | strip_literal %] + [% IF journal.score %]
    + Score: ([% journal.score %]) + [% END %] + +

    +[% END %] +[% PROCESS pagination %] +

    + +__seclev__ +100 +__version__ +$Id: journalsearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/nosearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/nosearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/nosearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,29 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +nosearch +__template__ +

    +

    Sorry, search is down at the moment. +Until it's back up, you may wish to search +[% constants.sitename %] through Google:
    +

    + + + +
    +
    +

    + +__seclev__ +100 +__version__ +$Id: nosearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/pagination;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/pagination;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/pagination;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,35 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +pagination +__template__ +[% IF (results.records_start > 0); + back = results.records_start - results.records_max; + IF back < 0; back = 0; END; + + last = results.records_max; + IF last > results.records_start; last = results.records_start; END; +%] +<Last [% last %] matches +[% END; + + IF ( (results.records_start > 0) && results.records_next ); +%] | [% + END; + + IF results.records_next; +%] +Next [% results.records_max %] matches> +[% END %] +__seclev__ +100 +__version__ +$Id: pagination;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/pollsearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/pollsearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/pollsearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,33 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +pollsearch +__template__ +[% FOREACH poll = results.records %] + [% skin = Slash.db.getSkin(poll.skin) %] + [% link = skin.url ? skin.url : gSkin.rootdir %] + [% poll.question %]
    + + On [% Slash.timeCalc(poll.date) %]
    + Voters: [% poll.voters %]
    + [% IF poll.score %] + Score: [% poll.score %] + [% END %] + +

    +[% END %] +[% PROCESS pagination %] +

    + +__seclev__ +100 +__version__ +$Id: pollsearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/searchform;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/searchform;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/searchform;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,154 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +searchform +__template__ +[% IF op == 'comments' || op == 'stories' || op == 'submissions' || op == 'polls'; + tref = Slash.db.getTopic(form.tid); + END; + IF op == 'stories' || op == 'submissions'; + sections = 1; + topics = 1; + END; +%] + +
    + +[% IF tref.image %] + [% tref.alttext %] +[% END %] + +
    +
    + + + [% IF op == 'stories'; + authors = Slash.db.getDescriptions("all-authors"); + newauthors = { "" => Slash.getData("all_authors") }; + FOREACH author = authors.keys; + newauthors.$author = authors.$author; + END; + Slash.createSelect("author", newauthors, form.author, 1, 0, 1); + END %] + + [% sort = Slash.db.getDescriptions('sortorder'); + Slash.createSelect("sort", sort, form.sort, 1) + %] + +
    + + Stories + Comments + Users + Polls + [% IF constants.search_journal_enabled %] + Journals + [% END %] + [% IF constants.rss_store %] + [% IF constants.search_rss_enabled || user.is_admin %] + RSS Headlines + [% END %] + [% END %] + [% IF constants.submiss_view || user.is_admin %] + Submissions + [% END %] +
    + + [% IF op == 'users' %] + Users with Journals + [% END %] + + [% IF op == 'submissions'; + submission_notes = Slash.db.getDescriptions('submission-notes'); + Slash.createSelect("note", submission_notes, form.note, 1, 0, 1); + END %] + + [% IF op == 'comments'; + formats = Slash.db.getDescriptions('threshcodes'); + threshold_select = Slash.createSelect('threshold', formats, form.threshold, 1); + %] + Threshold [% threshold_select %] + + [% END %] +

    +

    + +[% IF sections || topics %] +
    +[% + topics = Slash.db.getTopicTree(); + + listnames = {}; + IF form.tid; + topic_children = Slash.db.getAllChildrenTids(form.tid); + ELSE; + topic_children = topics.${constants.mainpage_nexus_tid}.children; + END; + + FOREACH t = topic_children; + NEXT IF !topics.$t.searchable; + listnames.${topics.$t.textname} = t; + END; + + listcount = listnames.size / 3; + listex = listnames.size mod 3; + i = 0; +%] +[% constants.sitename %] +[% IF !topics.${form.tid}.nexus && topics.${form.tid}.parent; + thisparent = topics.${form.tid}.parent.keys.nsort.0; + IF thisparent == constants.mainpage_nexus_tid; + thisparent = topics.${form.tid}.parent.keys.nsort.1; + END; + IF thisparent %] +:: [% topics.$thisparent.textname %] +[% END; END; IF form.tid %] +:: [% topics.${form.tid}.textname %] +[% END; IF listnames.size %] +Topics +[% END %] +
    + +[% IF listnames.size %] + + + +
    + +
      +[% FOREACH s = listnames.keys.sort -%] +
    • [% s %][% + IF user.is_admin %] [edit] [% +END %]
    • +[%- i = i + 1; + IF i == listcount.int || i == 0; + IF i == listcount.int && listex; + listext = listex = 1; + i = -1; + NEXT; + END; +%]
    + +
      [% END; END # FOREACH %] +
    +[% END # IF listnames.size %] + +[% END # IF sections || topics %] +
    + + +__seclev__ +100 +__version__ +$Id: searchform;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/searchrss;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/searchrss;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/searchrss;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,127 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +searchrss +__template__ +[% +rss.image = 1; +rss.items = []; +rss.channel = { + title => "$constants.sitename Search", + description => "$constants.sitename Search", + link => "$gSkin.absolutedir$env.script_name", +}; + +IF op == 'stories'; + FOREACH entry = results.records; + thisurl = Slash.db.getSkin(entry.primaryskid).url || gSkin.absolutedir; + thislink = thisurl _ '/article.pl?sid=' _ entry.sid; + rss.items.push({ + title => entry.title, + description => entry.introtext, + link => thislink, + time => entry.time, + creator => Slash.db.getUser(entry.uid, 'nickname'), + }); + END; + rss.channel.title = '$constants.sitename Story Search'; + rss.channel.description = '$constants.sitename Story Search'; + rss.rdfitemdesc = constants.search_rdfitemdesc; + rss.rdfitemdesc_html = constants.search_rdfitemdesc_html; + +ELSIF op == 'comments'; + FOREACH entry = results.records; + thislink = gSkin.absolutedir _ '/comments.pl?sid=' _ entry.did _ '&cid=' _ entry.cid; + thistime = Slash.timeCalc(entry.date); + rss.items.push({ + title => "$entry.subject ($thistime)", + link => thislink, + time => entry.date, + creator => Slash.db.getUser(entry.uid, 'nickname'), + }); + END; + rss.channel.title = '$constants.sitename Comment Search'; + rss.channel.description = '$constants.sitename Comment Search'; + +ELSIF op == 'users'; + FOREACH entry = results.records; + thisnick = entry.nickname | fixparam; + thislink = gSkin.absolutedir _ '/~' _ thisnick; + rss.items.push({ + title => entry.nickname, + link => thislink, + time => entry.journal_last_entry_date, + }); + END; + rss.channel.title = '$constants.sitename User Search'; + rss.channel.description = '$constants.sitename User Search'; + +ELSIF op == 'polls'; + FOREACH entry = results.records; + thisurl = Slash.db.getSkin(entry.primaryskid).url || gSkin.absolutedir; + thislink = thisurl _ '/pollBooth.pl?qid=' _ entry.qid; + thistime = Slash.timeCalc(entry.date); + rss.items.push({ + title => entry.nickname, + link => thislink, + time => entry.date, + }); + END; + rss.channel.title = '$constants.sitename Poll Search'; + rss.channel.description = '$constants.sitename Poll Search'; + +ELSIF op == 'journals'; + FOREACH entry = results.records; + thisnick = entry.nickname | fixparam; + thislink = gSkin.absolutedir _ '/~' _ thisnick _ '/journal/' _ entry.id; + thistime = Slash.timeCalc(entry.date); + rss.items.push({ + title => "$entry.description ($thistime)", + link => thislink, + time => entry.date, + creator => entry.nickname, + }); + END; + rss.channel.title = '$constants.sitename Journal Search'; + rss.channel.description = '$constants.sitename Journal Search'; + +ELSIF op == 'submissions'; + FOREACH entry = results.records; + thislink = gSkin.absolutedir _ '/submit.pl?subid=' _ entry.subid; + thistime = Slash.timeCalc(entry.date); + rss.items.push({ + title => "$entry.subj ($thistime)", + description => entry.story, + link => thislink, + time => entry.time, + }); + END; + rss.channel.title = '$constants.sitename Submission Search'; + rss.channel.description = '$constants.sitename Submission Search'; + rss.rdfitemdesc = constants.search_rdfitemdesc; + rss.rdfitemdesc_html = constants.search_rdfitemdesc_html; + +ELSIF op == 'test'; + FOREACH entry = results.records; + rss.items.push({ + title => entry, + link => gSkin.absolutedir _ '/search.pl?op=test' + }); + END; + rss.channel.title = '$constants.sitename Test Search'; + rss.channel.description = '$constants.sitename Test Search'; + +END; +%] +__seclev__ +100 +__version__ +$Id: searchrss;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/storysearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/storysearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/storysearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,48 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +storysearch +__template__ +[% FOREACH story=results.records %] + [% skin = Slash.db.getSkin(story.skid); + storylinks = Slash.linkStory({ + section => skin.name, + tid => story.tid, + tids => story.tids, + sid => story.sid, + 'link' => story.title + }) + %] +[% storylinks.1 | strip_html %] +[% IF user.is_admin %][ Edit ][% END %] +
    + On [% Slash.timeCalc(story.time, '%B %o, %Y') %] with [% story.commentcount %] comments
    + [% shorten( Slash.strip_notags(story.introtext) ) %]
    + + [% IF skin.name == 'mainpage' %]Main[% ELSE %][% skin.title %][% END %] > + [% FOREACH tid = story.tids %] + [% topic = Slash.db.getTopic(tid) %] + [% topic.textname %][% ", " UNLESS loop.last %] + [% END %] +
    + [% IF story.score %] + Score: [% story.score %]
    + [% END %] + +

    +[% END %] +[% PROCESS pagination %] +

    + +__seclev__ +100 +__version__ +$Id: storysearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/subsearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/subsearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/subsearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,44 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +subsearch +__template__ +

    +[% FOREACH entry = results.records %] + [% entry.subj %]
    + On [% Slash.timeCalc(entry.time) %]
    + [% shorten( Slash.strip_notags(entry.story) ) %]
    + + [% submission_state = Slash.db.getDescriptions('submission-state') %] + [% skin = Slash.db.getSkin(entry.skid) %] + Section: [% IF skin.name == 'mainpage' %]Main[% ELSE %][% skin.title %][% END %] > + [% FOREACH tid = entry.tid %] + [% topic = Slash.db.getTopic(tid) %] + [% topic.textname %][% ", " UNLESS loop.last %] + [% END %]
    + State: [% del = entry.del; submission_state.$del %]
    + [% IF entry.note %] + Note: [% entry.note %]
    + [% END %] + [% IF entry.score %] + Score: [% entry.score %]
    + [% END %] + +

    +[% END %] +

    +[% PROCESS pagination %] +

    + +__seclev__ +100 +__version__ +$Id: subsearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ Index: slashjp/plugins/SearchToo/templates/usersearch;searchtoo;default diff -u /dev/null slashjp/plugins/SearchToo/templates/usersearch;searchtoo;default:1.1 --- /dev/null Wed Jul 12 20:41:57 2006 +++ slashjp/plugins/SearchToo/templates/usersearch;searchtoo;default Wed Jul 12 20:41:57 2006 @@ -0,0 +1,53 @@ +__section__ +default +__description__ + +__title__ + +__page__ +searchtoo +__lang__ +en_US +__name__ +usersearch +__template__ + + [% FOREACH thisuser=results.records %] + + [% IF thisuser.score %] + + [% END %] + + [% IF thisuser.journal_last_entry_date %] + + [% ELSE %] + + [% END %] + [% UNLESS user.is_anon %] + + [% END %] + + [% END %] +
    + [% thisuser.score %] + + [% thisuser.nickname | strip_literal %]   + [% IF thisuser.fakeemail %] + ([% thisuser.uid %]) email: [% thisuser.fakeemail | strip_literal %]
    + [% ELSE %] + ([% thisuser.uid %])
    + [% END %] +
    + Last Journal entry [% Slash.timeCalc(thisuser.journal_last_entry_date) %] + +   + + [% PROCESS zoo_icons person=thisuser.uid %] +
    +[% PROCESS pagination %] +

    + +__seclev__ +100 +__version__ +$Id: usersearch;searchtoo;default,v 1.1 2006/07/12 11:41:57 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:58 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:58 +0900 Subject: [Slashdotjp-dev 482] CVS update: slashjp/plugins/Sections/templates Message-ID: <20060712114158.518DC2AC00E@users.sourceforge.jp> Index: slashjp/plugins/Sections/templates/data;sections;default diff -u slashjp/plugins/Sections/templates/data;sections;default:1.1.1.1 slashjp/plugins/Sections/templates/data;sections;default:1.2 --- slashjp/plugins/Sections/templates/data;sections;default:1.1.1.1 Wed Jan 28 06:55:07 2004 +++ slashjp/plugins/Sections/templates/data;sections;default Wed Jul 12 20:41:58 2006 @@ -23,20 +23,20 @@ [% CASE 'notadmin' %] [% returnme.data_constant = 1 %] -

    I woke up in the Soho bar when a policeman knew my name. He said,
    +	
    I woke up in the Soho bar when a policeman knew my name. He said,
              "You can go sleep at home tonite if you can get up and walk away."
              I staggered back to the underground and a breeze threw back my
              head. I remember throwing punches around and preachin' from my chair.
    -                         From 'Who Are You' by God (aka Pete Townshend)
    + From 'Who Are You' by God (aka Pete Townshend)
    [% CASE 'insert' %] - Inserted [% section %]
    + Inserted [% section %]
    [% CASE 'update' %] - Updated [% section %]
    + Updated [% section %]
    [% CASE 'failed' %] - Failed to create/update [% section %]
    + Failed to create/update [% section %]
    [% CASE 'addhead' %] [% returnme.data_constant = 1 %] @@ -53,15 +53,15 @@ Saving [% form.section | strip_nohtml %] Section [% CASE 'subsection_added' %] - Subsection '[% form.new_subsection %]' added.

    + Subsection '[% form.new_subsection %]' added.

    [% CASE 'subsection_removed' %] - Operation "[% form.action %]" completed.
    - Subsection #[% form.DEL_subsection %] removed.

    + Operation "[% form.action %]" completed.
    + Subsection #[% form.DEL_subsection %] removed.

    [% END %] __seclev__ 10000 __version__ -$Id: data;sections;default,v 1.1.1.1 2004/01/27 21:55:07 oliver Exp $ +$Id: data;sections;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Sections/templates/delSectCancel;sections;default diff -u slashjp/plugins/Sections/templates/delSectCancel;sections;default:1.1.1.1 slashjp/plugins/Sections/templates/delSectCancel;sections;default:1.2 --- slashjp/plugins/Sections/templates/delSectCancel;sections;default:1.1.1.1 Wed Jan 28 06:55:07 2004 +++ slashjp/plugins/Sections/templates/delSectCancel;sections;default Wed Jul 12 20:41:58 2006 @@ -12,8 +12,8 @@ __name__ delSectCancel __template__ -Canceled deletion of [% section %].
    +Canceled deletion of [% section %].
    __seclev__ 10000 __version__ -$Id: delSectCancel;sections;default,v 1.1.1.1 2004/01/27 21:55:07 oliver Exp $ +$Id: delSectCancel;sections;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Sections/templates/delSectConfirm;sections;default diff -u slashjp/plugins/Sections/templates/delSectConfirm;sections;default:1.1.1.1 slashjp/plugins/Sections/templates/delSectConfirm;sections;default:1.2 --- slashjp/plugins/Sections/templates/delSectConfirm;sections;default:1.1.1.1 Wed Jan 28 06:55:07 2004 +++ slashjp/plugins/Sections/templates/delSectConfirm;sections;default Wed Jul 12 20:41:58 2006 @@ -19,4 +19,4 @@ __seclev__ 10000 __version__ -$Id: delSectConfirm;sections;default,v 1.1.1.1 2004/01/27 21:55:07 oliver Exp $ +$Id: delSectConfirm;sections;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Sections/templates/delSection;sections;default diff -u slashjp/plugins/Sections/templates/delSection;sections;default:1.1.1.1 slashjp/plugins/Sections/templates/delSection;sections;default:1.2 --- slashjp/plugins/Sections/templates/delSection;sections;default:1.1.1.1 Wed Jan 28 06:55:07 2004 +++ slashjp/plugins/Sections/templates/delSection;sections;default Wed Jul 12 20:41:58 2006 @@ -13,16 +13,16 @@ __name__ delSection __template__ -
    -

    + +

    Do you really want to delete the [% section %] section? - - - -

    -
    + + + +

    + __seclev__ 10000 __version__ -$Id: delSection;sections;default,v 1.1.1.1 2004/01/27 21:55:07 oliver Exp $ +$Id: delSection;sections;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Sections/templates/editSection;sections;default diff -u slashjp/plugins/Sections/templates/editSection;sections;default:1.2 slashjp/plugins/Sections/templates/editSection;sections;default:1.3 --- slashjp/plugins/Sections/templates/editSection;sections;default:1.2 Fri Dec 31 21:37:15 2004 +++ slashjp/plugins/Sections/templates/editSection;sections;default Wed Jul 12 20:41:58 2006 @@ -19,39 +19,39 @@ editSection __template__ [ -Stories | -Submissions | -Preview +Stories | +Submissions | +Preview ] [% # Conditions for subsection delete confirmation. If true, show subform. IF form.DEL_subsection && !form.confirm; key = "del_subsection_${form.DEL_subsection}" %] -
    - Subsection action: [% form.$key %]? - - - - -    -   -
    -

    +
    + Subsection action: [% form.$key %]? + + + + +    +   +
    +

    [% END %] -
    - - + - -
    + +
    [% PROCESS formLabel value => "Section name" comment => "must be unique" %] - -

    + +

    [% PROCESS formLabel value="Article Count" comment="how many articles to display on section index" %] - - 1/3rd of these will display intro text, 2/3rds just headers

    + + 1/3rd of these will display intro text, 2/3rds just headers

    [% PROCESS formLabel value="Title" comment="be descriptive" %] -
    +
    [% IF qid.length %] [% PROCESS formLabel value="Polls for this section" comment="" %] @@ -61,149 +61,149 @@ [% PROCESS formLabel value="Type" comment="" %] [% types = Slash.db.getDescriptions("section-types") %] [% Slash.createSelect("type", types, this_section.type, 1) %] -

    +

    [% PROCESS formLabel value="Issue mode" comment="" %] [% issue %] -

    +

    [% PROCESS formLabel value="URL" comment="if the section has its own url" %] -
    +
    [% PROCESS formLabel value = "Hostname" comment = "Hostname we should match against" %] -
    +
    [% PROCESS formLabel value => "Cookiedomain" comment => "if the section requires that you give out a special cookie" %] -

    +

    [% PROCESS formLabel value => "Index Handler" comment => "the script that acts as / queries" %] -

    +

    [% IF blocks.size %] [% PROCESS formLabel value => "Edit Section slashboxes" comment => "blocks" %] [% FOREACH block = blocks %] -

  • - [% block.title %] - [% block.url %] +
  • + [% block.title %] + [% block.url %] [% IF block.ordernum && block.ordernum > 0 %] [% ' (default)' %] [% END %] [% END %] [% END %] -
    -
    +
    +
    - + [% INCLUDE titlebar title=>"Subsections" width=>"99%" %] - - -
    - - - + [% IF subsections.size %] - - - - - + + + + + [% END %] [% FOR ss=subsections %] - - - - - + + + + + [% END %] -
    + + + - + + + +
    + + + - -
    Enter name of new subsection: - - - -
    -

    -
    + +
    +

    +
    SubsectionArticle CountRemove Subsection
    SubsectionArticle CountRemove Subsection
    - - - - - -
    + + + + + +
    -

    +
    +

    [% IF form.addextra; extras.push(['','']); END; IF extras.size; INCLUDE titlebar title=>"Extra Story Fields", width=>"99%"; id = 1 %] - \n"; +
    \n"; [% FOR e=extras %] [% UNLESS loop.first %] - - + - - + + - - + + - + + [% END %] - - + + + - + - + - - + + [% id = id + 1; END %] -
    +
    [% INCLUDE spacer %] -
    +
    [% INCLUDE spacer %] -
    +
    [% INCLUDE spacer %] -
    +
    [% PROCESS formLabel value=>"Field Name:" comment='' %] - - + [% PROCESS formLabel value=>"Field Text:" %] - + [% nbsp=' '; nbsp.repeat(4) %] - + [% PROCESS formLabel value="Field Type:" %] [% Slash.createSelect( "extratype_$id", extra_types, e.type, 1) %] - -  Del?
    +  Del?
      -

    +

  •   +

    [% ELSE %] -
    +
    [% END %] -
    -
    -

    +
    +
    +
    [% IF this_section.type != 'collected' %] [% PROCESS formLabel value => "Topics" comment => "topics assigned to this section" %] - [% END %]   -
    -
    + + + + __seclev__ 10000 __version__ -$Id: editSection;sections;default,v 1.2 2004/12/31 12:37:15 oliver Exp $ +$Id: editSection;sections;default,v 1.3 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Sections/templates/listSections;sections;default diff -u slashjp/plugins/Sections/templates/listSections;sections;default:1.2 slashjp/plugins/Sections/templates/listSections;sections;default:1.3 --- slashjp/plugins/Sections/templates/listSections;sections;default:1.2 Fri Dec 24 05:13:45 2004 +++ slashjp/plugins/Sections/templates/listSections;sections;default Wed Jul 12 20:41:58 2006 @@ -14,14 +14,14 @@ listSections __template__ [% FOREACH section = sections %][% IF section.1 %] -

    [% section.0 %] [% section.1 %]

    [% END %] +

    [% section.0 %] [% section.1 %]

    [% END %] [% END %] -
    - -
    +
    + +
    __seclev__ 10000 __version__ -$Id: listSections;sections;default,v 1.2 2004/12/23 20:13:45 oliver Exp $ +$Id: listSections;sections;default,v 1.3 2006/07/12 11:41:58 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:58 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:58 +0900 Subject: [Slashdotjp-dev 483] CVS update: slashjp/plugins/Sections Message-ID: <20060712114158.2824B2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/Sections/PLUGIN diff -u slashjp/plugins/Sections/PLUGIN:1.2 slashjp/plugins/Sections/PLUGIN:1.3 --- slashjp/plugins/Sections/PLUGIN:1.2 Fri Dec 24 05:13:44 2004 +++ slashjp/plugins/Sections/PLUGIN Wed Jul 12 20:41:58 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:44 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:58 sugi Exp $ description="Sections Editor" name=Sections htdoc=sections.pl Index: slashjp/plugins/Sections/README.deprecated diff -u /dev/null slashjp/plugins/Sections/README.deprecated:1.1.2.1 --- /dev/null Wed Jul 12 20:41:58 2006 +++ slashjp/plugins/Sections/README.deprecated Wed Jul 12 20:41:58 2006 @@ -0,0 +1,5 @@ +This plugin is no longer required or useful, as of mid-2004. It will +be removed soon. However, having it installed does no harm. + +Jamie McCarthy +October 31, 2005 Index: slashjp/plugins/Sections/sections.pl diff -u slashjp/plugins/Sections/sections.pl:1.3 slashjp/plugins/Sections/sections.pl:1.4 --- slashjp/plugins/Sections/sections.pl:1.3 Fri Dec 31 21:37:15 2004 +++ slashjp/plugins/Sections/sections.pl Wed Jul 12 20:41:58 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: sections.pl,v 1.3 2004/12/31 12:37:15 oliver Exp $ +# $Id: sections.pl,v 1.4 2006/07/12 11:41:58 sugi Exp $ use strict; use Slash; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:58 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:58 +0900 Subject: [Slashdotjp-dev 484] CVS update: slashjp/plugins/Stats/Writer Message-ID: <20060712114158.AC5552AC00E@users.sourceforge.jp> Index: slashjp/plugins/Stats/Writer/Writer.pm diff -u slashjp/plugins/Stats/Writer/Writer.pm:1.3 slashjp/plugins/Stats/Writer/Writer.pm:1.4 --- slashjp/plugins/Stats/Writer/Writer.pm:1.3 Fri Dec 31 21:37:15 2004 +++ slashjp/plugins/Stats/Writer/Writer.pm Wed Jul 12 20:41:58 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Writer.pm,v 1.3 2004/12/31 12:37:15 oliver Exp $ +# $Id: Writer.pm,v 1.4 2006/07/12 11:41:58 sugi Exp $ package Slash::Stats::Writer; @@ -15,7 +15,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; # On a side note, I am not sure if I liked the way I named the methods either. # -Brian From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:59 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:59 +0900 Subject: [Slashdotjp-dev 485] CVS update: slashjp/plugins/Stock Message-ID: <20060712114159.250692AC00E@users.sourceforge.jp> Index: slashjp/plugins/Stock/PLUGIN diff -u slashjp/plugins/Stock/PLUGIN:1.2 slashjp/plugins/Stock/PLUGIN:1.3 --- slashjp/plugins/Stock/PLUGIN:1.2 Fri Dec 24 05:13:46 2004 +++ slashjp/plugins/Stock/PLUGIN Wed Jul 12 20:41:59 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:46 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:59 sugi Exp $ name=Stock description="stockquotes block" mysql_schema=mysql_schema.sql Index: slashjp/plugins/Stock/README diff -u slashjp/plugins/Stock/README:1.1.1.1 slashjp/plugins/Stock/README:1.2 --- slashjp/plugins/Stock/README:1.1.1.1 Wed Jan 28 06:55:10 2004 +++ slashjp/plugins/Stock/README Wed Jul 12 20:41:59 2006 @@ -1,6 +1,6 @@ Note that reproducing a third party's quotes without their permission may be prohibited by their terms and conditions, copyright law or other -laws in your area. VA Software, OSDN, and the Slash coders take no +laws in your area. VA Software, OSTG, and the Slash coders take no responsibility for how you use or misuse this software. Read the "perldoc Finance::Quote" page and the perldoc pages from its subclasses for more information, and if you are in doubt, consult a lawyer. You Index: slashjp/plugins/Stock/mysql_dump.sql diff -u slashjp/plugins/Stock/mysql_dump.sql:1.3 slashjp/plugins/Stock/mysql_dump.sql:1.4 --- slashjp/plugins/Stock/mysql_dump.sql:1.3 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stock/mysql_dump.sql Wed Jul 12 20:41:59 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_dump.sql,v 1.3 2004/12/31 12:37:16 oliver Exp $ +# $Id: mysql_dump.sql,v 1.4 2006/07/12 11:41:59 sugi Exp $ # INSERT INTO blocks (bid, block, seclev, type, description, skin, ordernum, title, portal, url, rdf, retrieve) VALUES ('stockquotes','',500,'static','','mainpage',8,'Stock Quotes',1,'','',0); Index: slashjp/plugins/Stock/mysql_schema.sql diff -u slashjp/plugins/Stock/mysql_schema.sql:1.2 slashjp/plugins/Stock/mysql_schema.sql:1.3 --- slashjp/plugins/Stock/mysql_schema.sql:1.2 Fri Dec 24 05:13:46 2004 +++ slashjp/plugins/Stock/mysql_schema.sql Wed Jul 12 20:41:59 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema.sql,v 1.2 2004/12/23 20:13:46 oliver Exp $ +# $Id: mysql_schema.sql,v 1.3 2006/07/12 11:41:59 sugi Exp $ # DROP TABLE IF EXISTS stocks; Index: slashjp/plugins/Stock/stockquotes.pl diff -u slashjp/plugins/Stock/stockquotes.pl:1.2 slashjp/plugins/Stock/stockquotes.pl:1.3 --- slashjp/plugins/Stock/stockquotes.pl:1.2 Fri Dec 24 05:13:46 2004 +++ slashjp/plugins/Stock/stockquotes.pl Wed Jul 12 20:41:59 2006 @@ -1,6 +1,6 @@ #!/usr/bin/perl -w -# $Id: stockquotes.pl,v 1.2 2004/12/23 20:13:46 oliver Exp $ +# $Id: stockquotes.pl,v 1.3 2006/07/12 11:41:59 sugi Exp $ use strict; use Slash; @@ -47,7 +47,7 @@ my $stock = $table->{$stock_key}; my($exch, $sym) = ($stock->{exchange}, $stock->{symbol}); my %stockfetch = $fq->fetch($exch, $sym); - if (!%stockfetch) { + if (!%stockfetch || !defined($stockfetch{$sym,"net"})) { slashdLog("failed stockfetch for '$stock_key' '$exch' '$sym'") if verbosity() >= 2; next; @@ -60,8 +60,9 @@ $stock->{year_lo} = sprintf("%.1f", $1); $stock->{year_hi} = sprintf("%.1f", $2); } - if ($stockfetch{$sym,"cap"} ne "" - and $stockfetch{$sym,"cap"} =~ /([\d.]+)([KMB])?/) { + if (defined $stockfetch{$sym,"cap"} + && $stockfetch{$sym,"cap"} ne "" + && $stockfetch{$sym,"cap"} =~ /([\d.]+)([KMB])?/) { $stock->{cap} = sprintf("%.0f$2", $1); } else { $stock->{cap} = "n/a"; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:58 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:58 +0900 Subject: [Slashdotjp-dev 486] CVS update: slashjp/plugins/Stats/templates Message-ID: <20060712114158.E74632AC0F4@users.sourceforge.jp> Index: slashjp/plugins/Stats/templates/calculate;stats;default diff -u slashjp/plugins/Stats/templates/calculate;stats;default:1.1.1.1 slashjp/plugins/Stats/templates/calculate;stats;default:1.2 --- slashjp/plugins/Stats/templates/calculate;stats;default:1.1.1.1 Wed Jan 28 06:55:09 2004 +++ slashjp/plugins/Stats/templates/calculate;stats;default Wed Jul 12 20:41:58 2006 @@ -165,4 +165,4 @@ __seclev__ 1000 __version__ -$Id: calculate;stats;default,v 1.1.1.1 2004/01/27 21:55:09 oliver Exp $ +$Id: calculate;stats;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/csv;stats;default diff -u slashjp/plugins/Stats/templates/csv;stats;default:1.1.1.1 slashjp/plugins/Stats/templates/csv;stats;default:1.2 --- slashjp/plugins/Stats/templates/csv;stats;default:1.1.1.1 Wed Jan 28 06:55:09 2004 +++ slashjp/plugins/Stats/templates/csv;stats;default Wed Jul 12 20:41:58 2006 @@ -31,4 +31,4 @@ __seclev__ 1000 __version__ -$Id: csv;stats;default,v 1.1.1.1 2004/01/27 21:55:09 oliver Exp $ +$Id: csv;stats;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/data;adminmail;default diff -u slashjp/plugins/Stats/templates/data;adminmail;default:1.1.1.1 slashjp/plugins/Stats/templates/data;adminmail;default:1.2 --- slashjp/plugins/Stats/templates/data;adminmail;default:1.1.1.1 Wed Jan 28 06:55:09 2004 +++ slashjp/plugins/Stats/templates/data;adminmail;default Wed Jul 12 20:41:58 2006 @@ -26,4 +26,4 @@ __seclev__ 500 __version__ -$Id: data;adminmail;default,v 1.1.1.1 2004/01/27 21:55:09 oliver Exp $ +$Id: data;adminmail;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/display;adminmail;default diff -u slashjp/plugins/Stats/templates/display;adminmail;default:1.3 slashjp/plugins/Stats/templates/display;adminmail;default:1.4 --- slashjp/plugins/Stats/templates/display;adminmail;default:1.3 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/display;adminmail;default Wed Jul 12 20:41:58 2006 @@ -64,7 +64,6 @@ [% END -%] [% END %] - accesslog: [% accesslog %] rows total formkeys: [% formkeys %] rows total comments: [% comments %] posted yesterday submissions: [% submissions %] submissions @@ -201,4 +200,4 @@ __seclev__ 100 __version__ -$Id: display;adminmail;default,v 1.3 2004/12/31 12:37:16 oliver Exp $ +$Id: display;adminmail;default,v 1.4 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/display;modmail;default diff -u slashjp/plugins/Stats/templates/display;modmail;default:1.3 slashjp/plugins/Stats/templates/display;modmail;default:1.4 --- slashjp/plugins/Stats/templates/display;modmail;default:1.3 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/display;modmail;default Wed Jul 12 20:41:58 2006 @@ -70,4 +70,4 @@ __seclev__ 100 __version__ -$Id: display;modmail;default,v 1.3 2004/12/31 12:37:16 oliver Exp $ +$Id: display;modmail;default,v 1.4 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/graph;stats;default diff -u slashjp/plugins/Stats/templates/graph;stats;default:1.1.1.1 slashjp/plugins/Stats/templates/graph;stats;default:1.2 --- slashjp/plugins/Stats/templates/graph;stats;default:1.1.1.1 Wed Jan 28 06:55:09 2004 +++ slashjp/plugins/Stats/templates/graph;stats;default Wed Jul 12 20:41:58 2006 @@ -84,4 +84,4 @@ __seclev__ 1000 __version__ -$Id: graph;stats;default,v 1.1.1.1 2004/01/27 21:55:09 oliver Exp $ +$Id: graph;stats;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/graphs;stats;default diff -u slashjp/plugins/Stats/templates/graphs;stats;default:1.3 slashjp/plugins/Stats/templates/graphs;stats;default:1.4 --- slashjp/plugins/Stats/templates/graphs;stats;default:1.3 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/graphs;stats;default Wed Jul 12 20:41:58 2006 @@ -86,8 +86,8 @@ CASE 'Hits'; IF (form.stats_skid && form.stats_skid != 0); - %] [% gtitle %] graph for [% form.stats_skid %] is unavailable. - Try the Pages graph instead. + %] [% gtitle %] graph for [% form.stats_skid %] is unavailable. + Try the Pages graph instead. [% # PROCESS make_graph # showtotal => 1, @@ -330,4 +330,4 @@ __seclev__ 1000 __version__ -$Id: graphs;stats;default,v 1.3 2004/12/31 12:37:16 oliver Exp $ +$Id: graphs;stats;default,v 1.4 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/list;stats;default diff -u slashjp/plugins/Stats/templates/list;stats;default:1.3 slashjp/plugins/Stats/templates/list;stats;default:1.4 --- slashjp/plugins/Stats/templates/list;stats;default:1.3 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/list;stats;default Wed Jul 12 20:41:58 2006 @@ -11,10 +11,10 @@ __name__ list __template__ - +
    [% IF form.stats_skid.defined && form.type != 'graphs' && stats_data.${form.stats_skid}.names %] [% PROCESS dumphead %] -

    +

    [% PROCESS doform label => "Individual Categories", select_box => Slash.createSelect('stats_name', stats_data.${form.stats_skid}.names, form.stats_name, 1) %] @@ -43,7 +43,7 @@ [% ELSIF form.graphname %] [% PROCESS graphshead %] -

    +

    [% PROCESS graphs gtitle => form.graphname %] [% ELSIF form.op == 'list' && form.type != 'graphs' %] @@ -54,70 +54,71 @@ [% ELSE %] [% PROCESS report %] -

    +

    [% PROCESS graphshead %] -

    +

    [% PROCESS dumphead %] [% END %] [% BLOCK dostats %] -

    [% myname %]
    +

    [% myname %]
    [% stats_total = 0 %] [% FOREACH day = stats_data.${form.stats_skid}.keys.sort; NEXT IF day == "names"; stats_num = stats_data.${form.stats_skid}.${day}.${myname} + 0; stats_total = stats_total + stats_num %] - [% day %]: [% stats_num %]
    + [% day %]: [% stats_num %]
    [% END %] - Total: [% stats_total %] + Total: [% stats_total %] [% PROCESS make_graph statdata => [myname] %] [% END %] [% BLOCK doform %] - [% PROCESS formLabel value => label, comment => comment %] -

    - [% select_box %] - -   Range: [% PROCESS stats_days %] - - - - -
    +
    +
    + List + [% PROCESS formLabel value => label, comment => comment %] + [% select_box %] +   Range: [% PROCESS stats_days %] + + + +
    +
    [% END %] [% BLOCK dumphead %] - [% PROCESS titlebar title => "Available Raw Stats for $constants.sitename", width => '100%' %] - -
    - - [% PROCESS formLabel value => "Section" %] - [% Slash.createSelect('stats_skid', skins, form.stats_skid, 1) %] - - - -
    + [% PROCESS titlebar title => "Available Raw Stats for $constants.sitename" %] +
    +
    + Stats + [% PROCESS formLabel value => "Section" %] + [% Slash.createSelect('stats_skid', skins, form.stats_skid, 1) %] + + +
    +
    [% END %] [% BLOCK graphshead %] - [% PROCESS titlebar title => "Available Graphs for $constants.sitename", width => '100%' %] - -
    - - [% PROCESS formLabel value => "Graphs" %] - [% PROCESS graphs # get mygraphs defined %] - [% Slash.createSelect('graphname', mygraphs, form.graphname, 1) %] -   Range: [% PROCESS stats_days %] -   Sections: [% Slash.createSelect('stats_skid', skins, form.stats_skid, 1) %] - - - - -
    + [% PROCESS titlebar title => "Available Graphs for $constants.sitename" %] +
    +
    + Graphs + [% PROCESS formLabel value => "Graphs" %] + [% PROCESS graphs # get mygraphs defined %] + [% Slash.createSelect('graphname', mygraphs, form.graphname, 1) %] +   Range: [% PROCESS stats_days %] +   Sections: [% Slash.createSelect('stats_skid', skins, form.stats_skid, 1) %] + + + +
    +
    [% END %] - +
    __seclev__ 1000 __version__ -$Id: list;stats;default,v 1.3 2004/12/31 12:37:16 oliver Exp $ +$Id: list;stats;default,v 1.4 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/make_graph;stats;default diff -u slashjp/plugins/Stats/templates/make_graph;stats;default:1.2 slashjp/plugins/Stats/templates/make_graph;stats;default:1.3 --- slashjp/plugins/Stats/templates/make_graph;stats;default:1.2 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/make_graph;stats;default Wed Jul 12 20:41:58 2006 @@ -16,32 +16,32 @@ END; IF (gtitle); - gtitle = gtitle | fixparam; + gtitle = gtitle | strip_paramattr; gtitle = '&title=' _ gtitle; END; UNLESS skid.defined; skid = form.stats_skid; END; - skid = skid | fixparam; + skid = skid | strip_paramattr; statstring = ''; FOREACH stat = statdata; IF (stat.0); - nstat = stat.0 | fixparam; + nstat = stat.0 | strip_paramattr; - nskid = stat.1 | fixparam; + nskid = stat.1 | strip_paramattr; IF (!nskid); nskid = skid; END; - nlabel = stat.2 | fixparam; - IF (!nskid); + nlabel = stat.2 | strip_paramattr; + IF (!nlabel); nlabel = ''; END; ELSE; - nstat = stat | fixparam; + nstat = stat | strip_paramattr; nskid = skid; nlabel = ''; END; @@ -49,14 +49,14 @@ statstring = statstring _ '&stats_graph_multiple=' _ nstat _ ',' _ nskid _ ',' _ nlabel; END; statstring = BLOCK -%] -&type=[% type | fixparam %]&stats_days=[% days | fixparam %]&byweekavg=[% byweekavg | fixparam %]&showtotal=[% showtotal | fixparam %][% statstring %][% gtitle %] +&type=[% type | strip_paramattr %]&stats_days=[% days | strip_paramattr %]&byweekavg=[% byweekavg | strip_paramattr %]&showtotal=[% showtotal | strip_paramattr %][% statstring %][% gtitle %] [%- END %] -

    - -

    +

    + +

    __seclev__ 1000 __version__ -$Id: make_graph;stats;default,v 1.2 2004/12/31 12:37:16 oliver Exp $ +$Id: make_graph;stats;default,v 1.3 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/report;stats;default diff -u slashjp/plugins/Stats/templates/report;stats;default:1.3 slashjp/plugins/Stats/templates/report;stats;default:1.4 --- slashjp/plugins/Stats/templates/report;stats;default:1.3 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/report;stats;default Wed Jul 12 20:41:58 2006 @@ -125,14 +125,14 @@ %] [% - "Relocated links
    "; + "Relocated links
    "; FOREACH key = stats_data_big.names.sort; - "$key
    "; + "$key
    "; PROCESS make_graph skid => '0', type => 'area', statdata => [ key ]; - "

    "; + "

    "; END; END; @@ -161,18 +161,21 @@ [% PROCESS titlebar title => ((reports.${form.report} || 'Available Reports') _ ' for ' _ constants.sitename), width => '100%' %] -

    + +
    + Reports [% PROCESS formLabel value => "Reports" %] [% Slash.createSelect('report', reports, form.report, 1) %]   Range: [% PROCESS stats_days %]   Sections: [% Slash.createSelect('stats_skid', skins, form.stats_skid, 1) %] - - - + + +
    + [% reportblock %] __seclev__ 1000 __version__ -$Id: report;stats;default,v 1.3 2004/12/31 12:37:16 oliver Exp $ +$Id: report;stats;default,v 1.4 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/stats_days;stats;default diff -u slashjp/plugins/Stats/templates/stats_days;stats;default:1.1.1.1 slashjp/plugins/Stats/templates/stats_days;stats;default:1.2 --- slashjp/plugins/Stats/templates/stats_days;stats;default:1.1.1.1 Wed Jan 28 06:55:10 2004 +++ slashjp/plugins/Stats/templates/stats_days;stats;default Wed Jul 12 20:41:58 2006 @@ -19,4 +19,4 @@ __seclev__ 1000 __version__ -$Id: stats_days;stats;default,v 1.1.1.1 2004/01/27 21:55:10 oliver Exp $ +$Id: stats_days;stats;default,v 1.2 2006/07/12 11:41:58 sugi Exp $ Index: slashjp/plugins/Stats/templates/table;stats;default diff -u slashjp/plugins/Stats/templates/table;stats;default:1.2 slashjp/plugins/Stats/templates/table;stats;default:1.3 --- slashjp/plugins/Stats/templates/table;stats;default:1.2 Fri Dec 31 21:37:16 2004 +++ slashjp/plugins/Stats/templates/table;stats;default Wed Jul 12 20:41:58 2006 @@ -13,40 +13,40 @@ __template__ [% PROCESS calculate %] -

    [% period %] Report for [% constants.sitename %]

    +

    [% period %] Report for [% constants.sitename %]

    -

    -Download CSV data for spreadsheet -

    +

    +Download CSV data for spreadsheet +

    -

    - +

    +

    - - + + [% pct = 100 div alldata.size; FOREACH this = alldata; NEXT IF loop.index == 0; myindex = loop.index - 1 %] - + [% END %] - + [% FOREACH day = days %] - - + + [% myindex = loop.index; FOREACH this = alldata; NEXT IF loop.index == 0 %] - + [% END %] - + [% END %] -
    [% alltypes.${myindex} %][% alltypes.${myindex} %]
    [% day %]
    [% day %][% Slash.commify(this.${myindex}) %][% Slash.commify(this.${myindex}) %]
    -

    + +

    __seclev__ 1000 __version__ -$Id: table;stats;default,v 1.2 2004/12/31 12:37:16 oliver Exp $ +$Id: table;stats;default,v 1.3 2006/07/12 11:41:58 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:59 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:59 +0900 Subject: [Slashdotjp-dev 487] CVS update: slashjp/plugins/Submit Message-ID: <20060712114159.7111F2AC00E@users.sourceforge.jp> Index: slashjp/plugins/Submit/PLUGIN diff -u slashjp/plugins/Submit/PLUGIN:1.2 slashjp/plugins/Submit/PLUGIN:1.3 --- slashjp/plugins/Submit/PLUGIN:1.2 Fri Dec 24 05:13:46 2004 +++ slashjp/plugins/Submit/PLUGIN Wed Jul 12 20:41:59 2006 @@ -1,7 +1,8 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:46 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:59 sugi Exp $ description="Submission System" name=Submit htdoc=submit.pl +mysql_dump=mysql_dump.sql template=templates/data;submit;default template=templates/displayForm;submit;default template=templates/formatSub;submit;default Index: slashjp/plugins/Submit/mysql_dump.sql diff -u /dev/null slashjp/plugins/Submit/mysql_dump.sql:1.1.2.1 --- /dev/null Wed Jul 12 20:41:59 2006 +++ slashjp/plugins/Submit/mysql_dump.sql Wed Jul 12 20:41:59 2006 @@ -0,0 +1,6 @@ +# +# $Id: mysql_dump.sql,v 1.1.2.1 2006/07/12 11:41:59 sugi Exp $ +# + +INSERT INTO vars (name, value, description) VALUES ('submissions_link_relnofollow', '0', 'Add a rel="nofollow" to the submitter\'s vanity link for all submissions?'); + Index: slashjp/plugins/Submit/submit.pl diff -u slashjp/plugins/Submit/submit.pl:1.4 slashjp/plugins/Submit/submit.pl:1.5 --- slashjp/plugins/Submit/submit.pl:1.4 Wed Nov 16 20:16:25 2005 +++ slashjp/plugins/Submit/submit.pl Wed Jul 12 20:41:59 2006 @@ -1,12 +1,12 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: submit.pl,v 1.4 2005/11/16 11:16:25 tach Exp $ +# $Id: submit.pl,v 1.5 2006/07/12 11:41:59 sugi Exp $ use strict; use Slash 2.003; # require Slash 2.3.x -use Slash::Constants qw(:messages); +use Slash::Constants qw(:messages :web); use Slash::Display; use Slash::Utility; use Slash::XML; @@ -18,17 +18,32 @@ my $constants = getCurrentStatic(); my $user = getCurrentUser(); my $form = getCurrentForm(); - my $formkey = $form->{formkey}; - my $formname = 'submissions'; - $form->{del} ||= 0; - $form->{op} ||= ''; - my $error_flag = 0; - my $success = 0; - - if (($form->{content_type} eq 'rss') and ($form->{op} eq 'list') and $constants->{submiss_view}) { - my $success = displayRSS($slashdb, $constants, $user, $form); - return if $success; + my $submiss_view = $constants->{submiss_view} || $user->{is_admin}; + + my %ops = ( + blankform => [1, \&blankForm], + previewstory => [1, \&previewStory], + pending => [!$user->{is_anon}, \&yourPendingSubmissions], + submitstory => [1, \&saveSub], + list => [$submiss_view, \&submissionEd], + viewsub => [$submiss_view, \&previewForm], + update => [$user->{is_admin}, \&updateSubmissions], + 'delete' => [$user->{is_admin}, \&deleteSubmissions], + merge => [$user->{is_admin}, \&mergeSubmissions], + changesubmission => [$user->{is_admin}, \&changeSubmission], + ); + + $ops{default} = $ops{blankform}; + + my $op = lc($form->{op} || 'default'); + $op = 'default' if !$ops{$op} || !$ops{$op}[ALLOWED]; + + $form->{del} ||= 0; + + if ($form->{content_type} && $form->{content_type} =~ $constants->{feed_types} + && $op eq 'list' && $submiss_view) { + return if displayRSS($slashdb, $constants, $user, $form); } # this really should not be done now, but later, it causes @@ -42,96 +57,57 @@ $form->{name} = strip_nohtml($form->{name}) if $form->{name}; # Show submission title on browser's titlebar. - my($tbtitle) = $form->{title}; - $tbtitle =~ s/^"?(.+?)"?$/$1/ if $tbtitle; - - my $ops = { - # initial form, no formkey needed due to 'preview' requirement - blankform => { - seclev => 0, - checks => ['max_post_check', 'generate_formkey'], - function => \&blankForm, - }, - previewstory => { - seclev => 0, - checks => ['update_formkeyid'], - function => \&previewStory, - }, - pending => { - seclev => 1, - function => \&yourPendingSubmissions, - }, - submitstory => { - function => \&saveSub, - seclev => 0, - post => 1, - checks => [ qw (max_post_check valid_check response_check - interval_check formkey_check) ], - }, - list => { - seclev => $constants->{submiss_view} ? 0 : 100, - function => \&submissionEd, - }, - viewsub => { - seclev => $constants->{submiss_view} ? 0 : 100, - function => \&previewForm, - }, - update => { - seclev => 100, - function => \&updateSubmissions, - }, - delete => { - seclev => 100, - function => \&deleteSubmissions, - }, - merge => { - seclev => 100, - function => \&mergeSubmissions, - }, - }; - - $ops->{default} = $ops->{blankform}; - - my $op = lc($form->{op}); - $op ||= 'default'; - $op = 'default' if ( - ($user->{seclev} < $ops->{$op}{seclev}) - || - ! $ops->{$op}{function} - ); + my($tbtitle); + if ($form->{subid} && $op ne "changesubmission") { + $tbtitle = $slashdb->getSubmission($form->{subid}, [ 'subj' ]); + $tbtitle = $tbtitle->{subj} if $tbtitle; + $tbtitle =~ s/^"?(.+?)"?$/$1/ if $tbtitle; + } # the submissions tab should always be highlighted, # being submit.pl and all - my $data = { - admin => 1, - tab_selected => 'submissions', - }; header( - getData('header', { tbtitle => $tbtitle } ), - '', $data + getData('header', { tbtitle => $tbtitle } ), '', { + admin => 1, + tab_selected => 'submissions', + } ) or return; - if ($user->{seclev} < 100) { - if ($ops->{$op}{checks}) { - for my $check (@{$ops->{$op}{checks}}) { - $ops->{$op}{update_formkey} = 1 - if ($check eq 'formkey_check'); - $error_flag = formkeyHandler( - $check, $formname, $formkey - ); - last if $error_flag; - } - } - } + $ops{$op}[FUNCTION]->($constants, $slashdb, $user, $form); - # call the method - $success = $ops->{$op}{function}->($constants, $slashdb, $user, $form) if ! $error_flag; + footer(); +} - if ($ops->{$op}{update_formkey} && $success && ! $error_flag) { - my $updated = $slashdb->updateFormkey($formkey, $form->{tid}, length($form->{story})); - } +################################################################# +# Update note, comment and skin with the option to delete based +# on extra form elements in the submission view. +sub changeSubmission { + my($constants, $slashdb, $user, $form) = @_; + my($gSkin, $subid) = (getCurrentSkin(), $form->{subid}); + my($option, $title); + + if (!$subid) { + submissionEd(@_); + } else { + $option->{nodelete} = 1 unless $form->{"del_$form->{subid}"}; - footer(); + # Must remove subid from $form when updating submission data + # since Slash::DB::MySQL::deleteSubmission() will make extra + # queries to the database if it exists. + delete $form->{subid}; + my @subids = $slashdb->deleteSubmission($option); + # Restore subid for proper functioning of the next page view. + $form->{subid} = $subid; + if (@subids) { + $title = getData('updatehead', { subids => \@subids }); + submissionEd(@_, $title); + } else { + # Behavior here was unspecified. I chose this route, + # although returning to submissionEd() would simplify + # things. - Cliff + submissionEd(@_, ""); + } + } } ################################################################# @@ -152,28 +128,68 @@ ################################################################# sub blankForm { my($constants, $slashdb, $user, $form) = @_; - yourPendingSubmissions(@_); - displayForm($user->{nickname}, 'http://'.$constants->{basedomain}.'/~'.$user->{nickname}.'/', $form->{skin}, getData('defaulthead')); + print getData('submit_body_open'); + yourPendingSubmissions($constants, $slashdb, $user, $form, { skip_submit_body => 1 }); + + my $reskey = getObject('Slash::ResKey'); + my $rkey = $reskey->key('submit'); + if ($rkey->create) { + displayForm($user->{nickname}, $user->{fakeemail}, $form->{skin}, getData('defaulthead')); + } else { + print $rkey->errstr; + } + + print getData('submit_body_close'); } ################################################################# sub previewStory { my($constants, $slashdb, $user, $form) = @_; - displayForm($form->{name}, $form->{email}, $form->{skin}, getData('previewhead')); + + my $error_message = ''; + + my $reskey = getObject('Slash::ResKey'); + my $rkey = $reskey->key('submit'); + unless ($rkey->touch) { + $error_message = $rkey->errstr; + if ($rkey->death) { + print $error_message; + return 0; + } + } + + displayForm($form->{name}, $form->{email}, $form->{skin}, getData('previewhead'), '', $error_message); } ################################################################# sub yourPendingSubmissions { - my($constants, $slashdb, $user, $form) = @_; - + my($constants, $slashdb, $user, $form, $options) = @_; + $options ||= {}; return if $user->{is_anon}; - + print getData("submit_body_open") unless $options->{skip_submit_body}; if (my $submissions = $slashdb->getSubmissionsByUID($user->{uid}, "", { limit_days => 365 })) { slashDisplay('yourPendingSubs', { submissions => $submissions, width => '100%', }); } + print getData("submit_body_close") unless $options->{skip_submit_body}; +} + +################################################################# +sub getSubmissionSelections { + my($constants) = @_; + + # Terminology mismatch..."selections" is legacy but the data is + # for submissions.note -- time for a nomenclature adjustment? + # - Cliff + my %selections = map { ($_, $_) } + (qw(Hold Quik), '', # '' is special + (ref $constants->{submit_categories} + ? @{$constants->{submit_categories}} : ()) + ); + + return \%selections; } ################################################################# @@ -184,6 +200,10 @@ my $sub = $slashdb->getSubmission($form->{subid}); + $slashdb->updateSubMemory($form->{submatch}, $form->{subnote}) if $form->{submatch} && $user->{is_admin}; + my($sub_memory, $subnotes_ref); + $sub_memory = $slashdb->getSubmissionMemory if $user->{is_admin}; + my @topics; my $topic = $slashdb->getTopic($sub->{tid}); @@ -201,6 +221,10 @@ $email_known = "mailto" if $sub->{email} eq $user->{fakeemail}; $sub->{email} = processSub($sub->{email}, $email_known); + my $last_admin_text = $slashdb->getLastSessionText($user->{uid}); + my $lasttime = $slashdb->getTime(); + $slashdb->setUser($user->{uid}, { adminlaststorychange => $lasttime }) if $last_admin_text ne $sub->{subj}; + $slashdb->setSession(getCurrentUser('uid'), { lasttitle => $sub->{subj}, last_subid => $form->{subid}, @@ -208,9 +232,13 @@ }) if $user->{is_admin}; my $num_from_uid = 0; + my $accepted_from_uid = 0; my $num_with_emaildomain = 0; + my $accepted_from_emaildomain = 0; if ($user->{is_admin}) { + $accepted_from_uid = $slashdb->countSubmissionsFromUID($sub->{uid}, { del => 2 }); $num_from_uid = $slashdb->countSubmissionsFromUID($sub->{uid}); + $accepted_from_emaildomain = $slashdb->countSubmissionsWithEmaildomain($sub->{emaildomain}, { del => 2 }); $num_with_emaildomain = $slashdb->countSubmissionsWithEmaildomain($sub->{emaildomain}); } @@ -233,28 +261,39 @@ # Max of 12 chars per word. $word = substr($word, 0, 12); } - if (length($sim->{title}) > 35) { - # Max of 35 char title. - $sim->{title} = substr($sim->{title}, 0, 30); - $sim->{title} =~ s/\s+\S+$//; - $sim->{title} .= "..."; - } + $sim->{title} = chopEntity($sim->{title}, 35); } } + foreach my $memory (@$sub_memory) { + my $match = $memory->{submatch}; + + if ($sub->{email} =~ m/$match/i || + $sub->{name} =~ m/$match/i || + $sub->{subj} =~ m/$match/i || + $sub->{ipid} =~ m/$match/i || + $sub->{story} =~ m/$match/i) { + push @$subnotes_ref, $memory; + } + } + slashDisplay('previewForm', { - submission => $sub, - submitter => $sub->{uid}, - subid => $form->{subid}, - topic => $topic, - ipid => $sub->{ipid}, - ipid_vis => $sub->{ipid_vis}, - admin_flag => $admin_flag, - extras => $extracolumns, - lockTest => lockTest($sub->{subj}), - similar_stories => $similar_stories, - num_from_uid => $num_from_uid, - num_with_emaildomain => $num_with_emaildomain, + submission => $sub, + submitter => $reader->getUser($sub->{uid}), + subid => $form->{subid}, + topic => $topic, + ipid => $sub->{ipid}, + ipid_vis => $sub->{ipid_vis}, + admin_flag => $admin_flag, + extras => $extracolumns, + lockTest => lockTest($sub->{subj}), + similar_stories => $similar_stories, + num_from_uid => $num_from_uid, + num_with_emaildomain => $num_with_emaildomain, + accepted_from_uid => $accepted_from_uid, + accepted_from_emaildomain => $accepted_from_emaildomain, + note_options => getSubmissionSelections($constants), + subnotes_ref => $subnotes_ref, }); } @@ -283,14 +322,19 @@ my($def_skin, $cur_skin, $def_note, $cur_note, $skins, @skins, @notes, %all_skins, %all_notes, %sn); + my $reader = getObject('Slash::DB', { db_type => 'reader' }); $form->{del} = 0 if $user->{is_admin}; + if (defined $form->{toggle_bin_refresh} && $user->{is_admin}) { + $slashdb->setUser($user->{uid}, { opt_disable_submit_bin_refresh => $form->{toggle_bin_refresh} ? 1 : 0 }); + } + $def_skin = getData('defaultskin'); $def_note = getData('defaultnote'); $cur_skin = $form->{skin} || $def_skin; $cur_note = $form->{note} || $def_note; - $skins = $slashdb->getSubmissionsSkins(); + $skins = $reader->getSubmissionsSkins(); for (@$skins) { my($skin, $note, $cnt) = @$_; @@ -303,7 +347,7 @@ for my $note_str (keys %all_notes) { $sn{$def_skin}{$note_str} = 0; for (grep { $_ ne $def_skin } keys %sn) { - $sn{$def_skin}{$note_str} += $sn{$_}{$note_str}; + $sn{$def_skin}{$note_str} += $sn{$_}{$note_str} || 0; } } @@ -332,7 +376,7 @@ width => '100%', }); - my($submissions, %selection); + my($submissions); $submissions = $slashdb->getSubmissionForUser; for my $sub (@$submissions) { @@ -341,28 +385,21 @@ $sub->{is_anon} = isAnon($sub->{uid}); my @strs = ( - substr($sub->{subj}, 0, 35), - substr($sub->{name}, 0, 20), - substr($sub->{email}, 0, 20) + chopEntity($sub->{subj}, 35), + chopEntity($sub->{name}, 20), + chopEntity($sub->{email}, 20) ); - $strs[0] .= '...' if length($sub->{subj}) > 35; $sub->{strs} = \@strs; my $skin = $slashdb->getSkin($sub->{primaryskid}); - $sub->{sskin} = $sub->{primaryskid} ne $constants->{mainpage_skid} ? "&skin=$skin->{name}" : ''; $sub->{stitle} = '&title=' . fixparam($sub->{subj}); + $sub->{skin} = $skin->{name}; } - %selection = map { ($_, $_) } - (qw(Hold Quik), '', # '' is special - (ref $constants->{submit_categories} - ? @{$constants->{submit_categories}} : ()) - ); - # Do we provide a submission list based on a custom sort? my @weighted; if ($constants->{submit_extra_sort_key}) { @@ -377,7 +414,7 @@ my $template = $user->{is_admin} ? 'Admin' : 'User'; slashDisplay('subEd' . $template, { submissions => $submissions, - selection => \%selection, + selection => getSubmissionSelections($constants), weighted => \@weighted, }); } @@ -397,7 +434,7 @@ }); } - xmlDisplay('rss', { + xmlDisplay($form->{content_type} => { channel => { title => "$constants->{sitename} Submissions", 'link' => "$gSkin->{absolutedir}/submit.pl?op=list", @@ -416,13 +453,13 @@ my $form = getCurrentForm(); my $user = getCurrentUser(); - if (length($form->{story}) > $constants->{max_submission_size}) { + if ($form->{story} && length($form->{story}) > $constants->{max_submission_size}) { titlebar('100%', getData('max_submissionsize_title')); print getData('max_submissionsize_err', { size => $constants->{max_submission_size}}); } my %keys_to_check = ( story => 1, subj => 1 ); - if ($error_message ne '') { + if ($error_message && $error_message ne '') { titlebar('100%', getData('filtererror', { err_message => $error_message})); print getData('filtererror', { err_message => $error_message }); } else { @@ -448,7 +485,7 @@ } my $skins = $slashdb->getSkins(); - my $topic_values = $slashdb->getDescriptions('highlighted-topics-submittable'); + my $topic_values = $slashdb->getDescriptions('non_nexus_topics-submittable'); my $skin_values = $slashdb->getDescriptions('skins-submittable'); $form->{tid} ||= 0; @@ -480,26 +517,16 @@ my $topic = $slashdb->getTopic($form->{tid}); my $known = ""; + $fakeemail ||= ''; if ($form->{email}) { $fakeemail = $form->{email}; - } elsif ($fakeemail eq $user->{fakeemail}) { + } elsif ($fakeemail && $user->{fakeemail} && $fakeemail eq $user->{fakeemail}) { $known = "mailto"; # we assume this is like if form.email is passed in - $fakeemail = strip_attribute($user->{fakeemail}); + $fakeemail = strip_attribute($fakeemail); } - my $fixedstory; - if ($form->{sub_type} && $form->{sub_type} eq 'plain') { - $fixedstory = strip_plaintext(url2html($form->{story})); - } else { - $fixedstory = strip_html(url2html($form->{story})); - - # some submitters like to add whitespace before and - # after their introtext. This is never wanted. --Pater - $fixedstory =~ s/^<(?:P|BR)(?:>|\s[^>]*>)//i; - $fixedstory =~ s/<(?:P|BR)(?:>|\s[^>]*>)$//i; - } - $fixedstory = balanceTags($fixedstory); + my $fixedstory = fixStory($form->{story}, { sub_type => $form->{sub_type} }); slashDisplay('displayForm', { fixedstory => $fixedstory, @@ -521,6 +548,18 @@ sub saveSub { my($constants, $slashdb, $user, $form) = @_; + my $reskey = getObject('Slash::ResKey'); + my $rkey = $reskey->key('submit'); + unless ($rkey->use) { + my $error_message = $rkey->errstr; + if ($rkey->death) { + print $error_message; + } else { + displayForm($form->{name}, $form->{email}, $form->{skin}, '', '', $error_message); + } + return 0; + } + $form->{name} ||= ''; if (length($form->{subj}) < 2) { @@ -547,12 +586,7 @@ } } - if ($form->{sub_type} && $form->{sub_type} eq 'plain') { - $form->{story} = strip_plaintext(url2html($form->{story})); - } else { - $form->{story} = strip_html(url2html($form->{story})); - } - $form->{story} = balanceTags($form->{story}); + $form->{story} = fixStory($form->{story}, { sub_type => $form->{sub_type} }); my $uid ||= $form->{name} ? getCurrentUser('uid') @@ -591,11 +625,14 @@ } } - - my $messagesub = { %$submission }; $messagesub->{subid} = $slashdb->createSubmission($submission); - # $slashdb->formSuccess($form->{formkey}, 0, length($form->{subj})); + + if ($form->{url_id}) { + my $url_id = $form->{url_id}; + my $globjid = $slashdb->getGlobjidCreate("submissions", $messagesub->{subid}); + $slashdb->addUrlForGlobj($url_id, $globjid); + } my $messages = getObject('Slash::Messages'); if ($messages) { @@ -605,21 +642,19 @@ subject => { template_name => 'messagenew_subj' }, submission => $messagesub, }; - for (@$users) { -# XXXSKIN - no "section" restriction -# my $user_section = $slashdb->getUser($_, 'section'); -# next if ($user_section && $user_section ne $messagesub->{section}); - $messages->create($_, MSG_CODE_NEW_SUBMISSION, $data); - } + $messages->create($users, MSG_CODE_NEW_SUBMISSION, $data) if @$users; } - + + + print getData("submit_body_open"); slashDisplay('saveSub', { title => 'Saving', width => '100%', missingemail => length($form->{email}) < 3, anonsubmit => isAnon($uid) && length($form->{name}) < 3 && length($form->{email}) < 3, }); - yourPendingSubmissions(@_); + yourPendingSubmissions($constants, $slashdb, $user, $form, { skip_submit_body => 1 }); + print getData("submit_body_close"); return(1); } @@ -640,40 +675,50 @@ } ################################################################# -sub url2html { - my($introtext) = @_; - $introtext =~ s/\n\n/\n

    /gi; - $introtext .= " "; - - # this is kinda experimental ... esp. the $extra line - # we know it can break real URLs, but probably will preserve - # real URLs more often than it will break them - $introtext =~ s{(?])(http|https|ftp|gopher|telnet)://([$URI::uric#]+)}{ - my($proto, $url) = ($1, $2); - my $extra = ''; - $extra = $1 if $url =~ s/([?!;:.,']+)$//; - $extra = ')' . $extra if $url !~ /\(/ && $url =~ s/\)$//; - qq[$proto://$url$extra]; - }ogie; - $introtext =~ s/\s+$//; - return $introtext; +sub fixStory { + my($str, $opts) = @_; + + if ($opts->{sub_type} && $opts->{sub_type} eq 'plain') { + $str = strip_plaintext(url2html($str)); + } else { + $str = strip_html(url2html($str)); + } + + # remove leading and trailing whitespace + $str =~ s/^$Slash::Utility::Data::WS_RE+//io; + $str =~ s/$Slash::Utility::Data::WS_RE+$//io; + + # and let's just get rid of these P tags; we don't need them, and they + # cause too many problems in submissions + unless (getCurrentStatic('submit_keep_p')) { + $str =~ s|

    ||g; + $str =~ s||

    |g; + } + + $str = balanceTags($str, { deep_nesting => 1 }); + + # do it again, just in case balanceTags added more ... + $str =~ s/^$Slash::Utility::Data::WS_RE+//io; + $str =~ s/$Slash::Utility::Data::WS_RE+$//io; + + return $str; } ################################################################# - sub genChosenHashrefForTopics { - my ($topics) = @_; + my($topics) = @_; my $constants = getCurrentStatic(); my $chosen_hr ={}; for my $tid (@$topics) { $chosen_hr->{$tid} = - $tid == $constants->{mainpage_tid} - ? 30 - : $constants->{topic_popup_defaultweight} || 10; + $tid == $constants->{mainpage_nexus_tid} + ? 30 + : $constants->{topic_popup_defaultweight} || 10; } return $chosen_hr; } + createEnvironment(); main(); From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:59 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:59 +0900 Subject: [Slashdotjp-dev 488] CVS update: slashjp/plugins/Stock/templates Message-ID: <20060712114159.431BC2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/Stock/templates/stockquotes;misc;default diff -u slashjp/plugins/Stock/templates/stockquotes;misc;default:1.1.1.1 slashjp/plugins/Stock/templates/stockquotes;misc;default:1.2 --- slashjp/plugins/Stock/templates/stockquotes;misc;default:1.1.1.1 Wed Jan 28 06:55:10 2004 +++ slashjp/plugins/Stock/templates/stockquotes;misc;default Wed Jul 12 20:41:59 2006 @@ -20,29 +20,29 @@ __name__ stockquotes __template__ - - - - - - - +
    Corp.$now$year$cap
    + + + + + + [% FOR stock = stocks %] - - - - - - + + + + + + [% END %] -
    Corp.$now$year$cap
    [% stock.name %] [% stock.last %] [% stock.year_lo %]-[% stock.year_hi %] [% stock.cap %]
    [% stock.name %] [% stock.last %] [% stock.year_lo %]-[% stock.year_hi %] [% stock.cap %]
    -
    Last update: + +
    Last update: [% last_update %] (15+ min delay). For informational purposes only. Not intended for trading purposes. If you're silly enough to do something based on this data, we're not liable.
    Data courtesy -Finance::Quote.
    +Finance::Quote. __seclev__ 500 __version__ -$Id: stockquotes;misc;default,v 1.1.1.1 2004/01/27 21:55:10 oliver Exp $ +$Id: stockquotes;misc;default,v 1.2 2006/07/12 11:41:59 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:41:59 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:41:59 +0900 Subject: [Slashdotjp-dev 489] CVS update: slashjp/plugins/Subscribe Message-ID: <20060712114159.D3D042AC0F4@users.sourceforge.jp> Index: slashjp/plugins/Subscribe/PLUGIN diff -u slashjp/plugins/Subscribe/PLUGIN:1.2 slashjp/plugins/Subscribe/PLUGIN:1.3 --- slashjp/plugins/Subscribe/PLUGIN:1.2 Fri Dec 24 05:13:47 2004 +++ slashjp/plugins/Subscribe/PLUGIN Wed Jul 12 20:41:59 2006 @@ -1,4 +1,4 @@ -# $Id: PLUGIN,v 1.2 2004/12/23 20:13:47 oliver Exp $ +# $Id: PLUGIN,v 1.3 2006/07/12 11:41:59 sugi Exp $ name=Subscribe description="Subscription system" htdoc=subscribe.pl @@ -11,3 +11,5 @@ template=templates/grant;subscribe;default template=templates/paypalbut;subscribe;default template=templates/grant;subscribe;default +template=templates/sub_low_msg;misc;default +template=templates/sub_out_msg;misc;default Index: slashjp/plugins/Subscribe/README diff -u slashjp/plugins/Subscribe/README:1.1.1.1 slashjp/plugins/Subscribe/README:1.2 --- slashjp/plugins/Subscribe/README:1.1.1.1 Wed Jan 28 06:55:11 2004 +++ slashjp/plugins/Subscribe/README Wed Jul 12 20:41:59 2006 @@ -2,7 +2,7 @@ The secret word is so you can set up purchasing sponsorships however you prefer to do it, without having to worry about firewalls or writing -complex code. It's not especially secure so if you're concerned about +complex code. It's not inherently secure so if you're concerned about users illicitly sponsoring pages on your website, please consider the security issues carefully. An overview of those issues is below. @@ -16,7 +16,7 @@ will be simple. When the user with uid 123 purchases 456 pages, and if your secret word is "foo", you just access this URL from anywhere: - http://yoursite.com/subscribe.pl?uid=123&buymore=456&secretword=foo + http://yoursite.com/subscribe.pl?uid=123&buymore=456&secretword=foo&op=save If you have a fancy credit-card processing server somewhere, set it up to hit that URL. If you take checks yourself, just type it into @@ -28,7 +28,8 @@ be sniffed. But then, if someone is sniffing your webservers' traffic you probably have bigger problems (your admins probably hit /admin.pl over non-secure HTTP, which means their cookies' username/password can -be sniffed too...) +be sniffed too... oh and hey, while you're thinking of it, set up an +https server so your admins can surf securely). Also, as usual, anyone that has read access to your DBIx/Password.pm can read this, but again, if an unauthorized party has such access, Index: slashjp/plugins/Subscribe/Subscribe.pm diff -u slashjp/plugins/Subscribe/Subscribe.pm:1.3 slashjp/plugins/Subscribe/Subscribe.pm:1.4 --- slashjp/plugins/Subscribe/Subscribe.pm:1.3 Fri Dec 31 21:37:17 2004 +++ slashjp/plugins/Subscribe/Subscribe.pm Wed Jul 12 20:41:59 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Subscribe.pm,v 1.3 2004/12/31 12:37:17 oliver Exp $ +# $Id: Subscribe.pm,v 1.4 2006/07/12 11:41:59 sugi Exp $ package Slash::Subscribe; @@ -15,7 +15,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.4 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class) = @_; Index: slashjp/plugins/Subscribe/mysql_dump diff -u slashjp/plugins/Subscribe/mysql_dump:1.2 slashjp/plugins/Subscribe/mysql_dump:1.3 --- slashjp/plugins/Subscribe/mysql_dump:1.2 Fri Dec 24 05:13:47 2004 +++ slashjp/plugins/Subscribe/mysql_dump Wed Jul 12 20:41:59 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_dump,v 1.2 2004/12/23 20:13:47 oliver Exp $ +# $Id: mysql_dump,v 1.3 2006/07/12 11:41:59 sugi Exp $ # INSERT INTO menus (menu, label, sel_label, value, seclev, showanon, menuorder) VALUES ('users','Subscription','subscription','/subscribe.pl',1,0,30); @@ -23,3 +23,6 @@ INSERT INTO vars (name, value, description) VALUES ('subscribe_hits_btmd', 10, 'Hits Bought Today Max Default, the default maximum number of hits that a user will be allowed to buy in one day, 0 for no (default) maximum'); INSERT INTO vars (name, value, description) VALUES ('subscribe_hits_only', 1, '0=All users get users_hits updated, 1=Only subscribed users'); INSERT INTO vars (name, value, description) VALUES ('subscribe_secretword', 'changemenow', 'Secret word to buy pages with'); + +INSERT INTO message_codes (code, type, seclev, modes, send, subscribe) VALUES (15, 'Subscription Running Low', 1, '', 'now', 1); +INSERT INTO message_codes (code, type, seclev, modes, send, subscribe) VALUES (16, 'Subscription Expired', 1, '', 'now', 1); Index: slashjp/plugins/Subscribe/mysql_schema diff -u slashjp/plugins/Subscribe/mysql_schema:1.2 slashjp/plugins/Subscribe/mysql_schema:1.3 --- slashjp/plugins/Subscribe/mysql_schema:1.2 Fri Dec 24 05:13:47 2004 +++ slashjp/plugins/Subscribe/mysql_schema Wed Jul 12 20:41:59 2006 @@ -1,5 +1,5 @@ # -# $Id: mysql_schema,v 1.2 2004/12/23 20:13:47 oliver Exp $ +# $Id: mysql_schema,v 1.3 2006/07/12 11:41:59 sugi Exp $ # ALTER TABLE users_hits ADD COLUMN hits_bought INT DEFAULT 0 NOT NULL AFTER hits, ADD COLUMN hits_bought_today SMALLINT UNSIGNED DEFAULT 0 NOT NULL AFTER hits_bought, ADD COLUMN hits_paidfor INT DEFAULT 0 NOT NULL AFTER hits_bought_today; Index: slashjp/plugins/Subscribe/subscribe.pl diff -u slashjp/plugins/Subscribe/subscribe.pl:1.3 slashjp/plugins/Subscribe/subscribe.pl:1.4 --- slashjp/plugins/Subscribe/subscribe.pl:1.3 Fri Dec 31 21:37:17 2004 +++ slashjp/plugins/Subscribe/subscribe.pl Wed Jul 12 20:41:59 2006 @@ -1,8 +1,8 @@ #!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: subscribe.pl,v 1.3 2004/12/31 12:37:17 oliver Exp $ +# $Id: subscribe.pl,v 1.4 2006/07/12 11:41:59 sugi Exp $ use strict; Index: slashjp/plugins/Subscribe/subscribemail.pl diff -u slashjp/plugins/Subscribe/subscribemail.pl:1.3 slashjp/plugins/Subscribe/subscribemail.pl:1.4 --- slashjp/plugins/Subscribe/subscribemail.pl:1.3 Fri Dec 31 21:37:17 2004 +++ slashjp/plugins/Subscribe/subscribemail.pl Wed Jul 12 20:41:59 2006 @@ -1,8 +1,10 @@ #!/usr/bin/perl -w -# $Id: subscribemail.pl,v 1.3 2004/12/31 12:37:17 oliver Exp $ + +# $Id: subscribemail.pl,v 1.4 2006/07/12 11:41:59 sugi Exp $ use strict; +use Slash::Constants qw(:messages); use vars qw( %task $me ); @@ -315,6 +317,84 @@ } slashdLog('Send Subscribe Mail End'); + slashdLog("Low Subscription and Expiration Warnings Begin"); + my $low_run = $sub_static->getLowRunningSubs(); + my $expire_sub = $sub_static->getExpiredSubs(); + my $messages = getObject("Slash::Messages"); + if ($messages) { + foreach my $uid (@$low_run) { + my $low_user = $slashdb->getUser($uid); + + my $last_warn = $low_user->{subscription_low_last_ts} || 0; + my $last_payment = $slashdb->sqlSelect("MAX(UNIX_TIMESTAMP(ts))", + "subscribe_payments", "uid=$uid"); + + # Users who were gifted subscriptions (perhaps + # by admins) get the warning too. + $last_payment = 0 if !$last_payment; + + # Under no circumstances send this message more + # than once a week. + next if $last_warn + 86400*6.5 > time; + + # Send this warning only once per payment. + # If the user already got this warning once + # since the time they last subscribed, + # don't send them another. Note this can + # fail to send a 2nd warning if a user gets + # multiple gifted subscriptions, but that's + # not a big deal. + next if $last_payment < $last_warn; + + # send message + my $users = $messages->checkMessageCodes( + MSG_CODE_SUBSCRIPTION_LOW, [$uid] + ); + my $low_val = int (( getCurrentStatic('paypal_num_pages') || 1000) / 20); + if (@$users) { + my $data = { + template_name => 'sub_low_msg', + subject => 'Subscription Running Low', + sub_low_value => $low_val + }; + $messages->create($users->[0], MSG_CODE_SUBSCRIPTION_LOW, $data, 0, '', 'now'); + } + $slashdb->setUser($uid, { subscription_low_last_ts => time() }); + } + + foreach my $uid (@$expire_sub) { + my $expire_user = $slashdb->getUser($uid); + + my $last_expire = $expire_user->{subscription_expire_last_ts} || 0; + my $last_payment = $slashdb->sqlSelect("MAX(UNIX_TIMESTAMP(ts))", "subscribe_payments", "uid=$uid"); + # Users who were gifted subscriptions (perhaps + # by admins) get the message too. + $last_payment = 0 if !$last_payment; + + # Under no circumstances send this message more + # than once a week. + next if $last_expire + 86400*6.5 > time; + + # Send this warning only once per payment. + # (See above.) + next if $last_payment < $last_expire; + + # send message + my $users = $messages->checkMessageCodes( + MSG_CODE_SUBSCRIPTION_OUT, [$uid] + ); + if (@$users) { + my $data = { + template_name => 'sub_out_msg', + subject => 'Subscription Expired' + }; + $messages->create($users->[0], MSG_CODE_SUBSCRIPTION_OUT, $data, 0, '', 'now'); + } + $slashdb->setUser($uid, { subscription_expire_last_ts => time() }); + } + } + slashdLog("Low Subscription and Expiration Warnings End"); + return ; }; @@ -323,6 +403,9 @@ $value ||= $stats->getStatLastNDays($name, 30) || 0; $statsSave->createStatDaily("${name}_last30", $value); push @$stats_ar, $value; + + + } 1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:42:00 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:42:00 +0900 Subject: [Slashdotjp-dev 490] CVS update: slashjp/plugins/Subscribe/Static Message-ID: <20060712114200.0A2A92AC00E@users.sourceforge.jp> Index: slashjp/plugins/Subscribe/Static/Static.pm diff -u slashjp/plugins/Subscribe/Static/Static.pm:1.2 slashjp/plugins/Subscribe/Static/Static.pm:1.3 --- slashjp/plugins/Subscribe/Static/Static.pm:1.2 Fri Dec 24 05:13:47 2004 +++ slashjp/plugins/Subscribe/Static/Static.pm Wed Jul 12 20:41:59 2006 @@ -1,7 +1,7 @@ # This code is a part of Slash, and is released under the GPL. -# Copyright 1997-2004 by Open Source Development Network. See README +# Copyright 1997-2005 by Open Source Technology Group. See README # and COPYING for more information, or see http://slashcode.com/. -# $Id: Static.pm,v 1.2 2004/12/23 20:13:47 oliver Exp $ +# $Id: Static.pm,v 1.3 2006/07/12 11:41:59 sugi Exp $ package Slash::Subscribe::Static; @@ -16,7 +16,7 @@ use base 'Slash::DB::Utility'; use base 'Slash::DB::MySQL'; -($VERSION) = ' $Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; +($VERSION) = ' $Revision: 1.3 $ ' =~ /\$Revision:\s+([^\s]+)/; sub new { my($class, $vuser) = @_; @@ -114,6 +114,27 @@ } ); } +sub getLowRunningSubs { + my ($self) = @_; + my $low_val = int ((getCurrentStatic('paypal_num_pages') || 1000) / 20); + print STDERR "low_val: $low_val\n"; + return $self->sqlSelectColArrayref( + 'users_hits.uid', + 'users_hits', + "hits_paidfor > 0 and (hits_paidfor - hits_bought) BETWEEN 1 AND $low_val" + ); +} + +sub getExpiredSubs { + my ($self) = @_; + return $self->sqlSelectColArrayref( + 'users_hits.uid', + 'users_hits', + 'hits_paidfor > 0 and (hits_paidfor - hits_bought) = 0' + ); +} + + sub _getUidsForPaymentType { my ($self, $type) = @_; my $ar = $self->sqlSelectColArrayref("DISTINCT uid", "subscribe_payments","payment_type = ".$self->sqlQuote($type)); From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:42:00 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:42:00 +0900 Subject: [Slashdotjp-dev 491] CVS update: slashjp/plugins/Unsubscribe Message-ID: <20060712114200.D2B4D2AC0CF@users.sourceforge.jp> Index: slashjp/plugins/Unsubscribe/PLUGIN diff -u /dev/null slashjp/plugins/Unsubscribe/PLUGIN:1.1 --- /dev/null Wed Jul 12 20:42:00 2006 +++ slashjp/plugins/Unsubscribe/PLUGIN Wed Jul 12 20:42:00 2006 @@ -0,0 +1,6 @@ +name=Unsubscribe +description="User Unsubscribe Page for Admins" +htdoc=unsubscribe.pl +requiresplugin=Admin +template=templates/form;unsubscribe;default +template=templates/data;unsubscribe;default Index: slashjp/plugins/Unsubscribe/unsubscribe.pl diff -u /dev/null slashjp/plugins/Unsubscribe/unsubscribe.pl:1.1 --- /dev/null Wed Jul 12 20:42:00 2006 +++ slashjp/plugins/Unsubscribe/unsubscribe.pl Wed Jul 12 20:42:00 2006 @@ -0,0 +1,87 @@ +#!/usr/bin/perl -w +# This code is a part of Slash, and is released under the GPL. +# Copyright 1997-2005 by Open Source Technology Group. See README +# and COPYING for more information, or see http://slashcode.com/. +# $Id: unsubscribe.pl,v 1.1 2006/07/12 11:42:00 sugi Exp $ + +use strict; +use File::Path; +use Slash 2.003; # require Slash 2.3.x +use Slash::Constants qw(:messages :web); +use Slash::Display; +use Slash::Utility; +use Time::HiRes qw( usleep ); + +sub main { + my $slashdb = getCurrentDB(); + my $constants = getCurrentStatic(); + my $user = getCurrentUser(); + my $form = getCurrentForm(); + my $gSkin = getCurrentSkin(); + + my $allowed = ($user->{acl}{unsubscribe} || ($user->{seclev} >= ($constants->{stats_admin_seclev} || 100))); + + # possible value of "op" parameter in form + my %ops = ( + unsubscribe => [ $allowed, \&unsubscribe ], + default => [ $allowed, \&showForm ] + ); + + # prepare op to proper value if bad value given + my $op = $form->{op}; + if (!$op || !exists $ops{$op} || !$ops{$op}[ALLOWED]) { + $op = 'default'; + } + + if (!$ops{$op}[ALLOWED]) { + redirect("$gSkin->{rootdir}/"); + return; + } + + header('', '', { admin => 1, adminmenu => 'config', tab_selected => 'unsubscribe' }) or return; + print createMenu('unsubscribe'); + + $ops{$op}[FUNCTION]->($slashdb, $constants, $user, $form); + + footer(); +} + +sub unsubscribe { + my($slashdb, $constants, $user, $form) = @_; + + my $goodcount = my $badcount = 0; + my @emails = split /\n/, $form->{emails}; + + foreach my $email (@emails) { + chomp $email; + + my $uid = $slashdb->sqlSelect('uid','users', + 'realemail=' . $slashdb->sqlQuote($email)); + + unless ($uid) { + $badcount++; + usleep 100; + next; + } + + $slashdb->sqlUpdate('users_info', { maillist => 0 }, "uid=$uid"); + $slashdb->sqlUpdate('users_messages', { mode => MSG_MODE_NONE }, + "uid=$uid AND mode=" . MSG_MODE_EMAIL); + + $goodcount++; + usleep 100; + } + + print getData('users-unsubscribed', { goodcount => $goodcount, badcount => $badcount }); +} + +sub showForm { + my($slashdb, $constants, $user, $form) = @_; + + slashDisplay ('form'); +} + +createEnvironment(); +main(); + +1; From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:42:01 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:42:01 +0900 Subject: [Slashdotjp-dev 492] CVS update: slashjp/plugins/Validator/templates Message-ID: <20060712114201.5C8CC2AC00E@users.sourceforge.jp> Index: slashjp/plugins/Validator/templates/html_invalid;misc;default diff -u /dev/null slashjp/plugins/Validator/templates/html_invalid;misc;default:1.1 --- /dev/null Wed Jul 12 20:42:01 2006 +++ slashjp/plugins/Validator/templates/html_invalid;misc;default Wed Jul 12 20:42:01 2006 @@ -0,0 +1,35 @@ +__section__ +default +__description__ + +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +html_invalid +__template__ +[% data_type = opts.data_type ? " in $opts.data_type" : ''; + data_id = opts.data_id ? " id $opts.data_id" : ''; +%] + +[% IF msg.mode == 1 %] + +

    Invalid HTML input was detected[% data_type; data_id %]:

    + +
    [% html | strip_literal %]
    + +[% ELSE %] + +Invalid HTML input was detected[% data_type; data_id %]: + +[% html %] + +[% END %] + +__seclev__ +500 +__version__ +$Id: html_invalid;misc;default,v 1.1 2006/07/12 11:42:01 sugi Exp $ Index: slashjp/plugins/Validator/templates/html_invalid_subj;misc;default diff -u /dev/null slashjp/plugins/Validator/templates/html_invalid_subj;misc;default:1.1 --- /dev/null Wed Jul 12 20:42:01 2006 +++ slashjp/plugins/Validator/templates/html_invalid_subj;misc;default Wed Jul 12 20:42:01 2006 @@ -0,0 +1,18 @@ +__section__ +default +__description__ + +__title__ + +__page__ +misc +__lang__ +en_US +__name__ +html_invalid_subj +__template__ +Invalid HTML Input +__seclev__ +500 +__version__ +$Id: html_invalid_subj;misc;default,v 1.1 2006/07/12 11:42:01 sugi Exp $ From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:42:01 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:42:01 +0900 Subject: [Slashdotjp-dev 493] CVS update: slashjp/plugins/Validator/validator Message-ID: <20060712114201.7B3612AC0CF@users.sourceforge.jp> Index: slashjp/plugins/Validator/validator/README.cvs diff -u /dev/null slashjp/plugins/Validator/validator/README.cvs:1.1 --- /dev/null Wed Jul 12 20:42:01 2006 +++ slashjp/plugins/Validator/validator/README.cvs Wed Jul 12 20:42:01 2006 @@ -0,0 +1,34 @@ +

    +This is the code for the W3C +HTML validation service. For information on installing it, +please see the source +code page. +

    + +

    + Our CVS base is available read-only, using CVS pserver + authentication a la: +

    +
    +    bash$ export CVSROOT=":pserver:anonymous ¡÷ dev.w3.org:/sources/public"
    +    bash$ cvs login
    +    (Logging in to anonymous ¡÷ dev.w3.org)
    +    CVS password: anonymous
    +    bash$ cvs get -r validator-0_6_5 validator
    +    cvs server: Updating validator
    +    cvs server: Updating validator/htdocs
    +    U validator/htdocs/about.html
    +    ...
    +          
    +

    + This will get you the current beta version. For intermediate + updates, use the validator-0_6_0-branch branch tag + instead. This is really what you want if you wish to install + a working version!

    +

    + Major new development is done in HEAD and + the trunk is more or less guaranteed to be in a state of greater + or lesser breakage at any given point in time. Approach with + great caution! +

    + From sugi ¡÷ users.sourceforge.jp Wed Jul 12 20:42:03 2006 From: sugi ¡÷ users.sourceforge.jp (Tatsuki SUGIURA) Date: Wed, 12 Jul 2006 20:42:03 +0900 Subject: [Slashdotjp-dev 494] CVS update: slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML Message-ID: <20060712114203.208942AC0CF@users.sourceforge.jp> Index: slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML/15445.dcl diff -u /dev/null slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML/15445.dcl:1.1 --- /dev/null Wed Jul 12 20:42:03 2006 +++ slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML/15445.dcl Wed Jul 12 20:42:02 2006 @@ -0,0 +1,95 @@ + Index: slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML/15445.dtd diff -u /dev/null slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML/15445.dtd:1.1 --- /dev/null Wed Jul 12 20:42:03 2006 +++ slashjp/plugins/Validator/validator/htdocs/sgml-lib/ISO-HTML/15445.dtd Wed Jul 12 20:42:02 2006 @@ -0,0 +1,693 @@ + + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + and elements. When both ID and NAME values are provided + for an element, the values shall be identical. It is an error for an + ID or NAME value to be associated with more than one element in a + document. + + It is recommended that authors of documents specify both the ID + attribute and the NAME attribute for the and elements. + -- + ID ID #IMPLIED -- Document-wide unique id -- + TITLE CDATA #IMPLIED -- Advisory title or amplification --" > + + + + + + + + + + + + + + + + + + + + + + +%HTMLlat1;%HTMLsymbol;%HTMLspecial; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + element shall not be surrounded with + quotation marks. These may be added by the user agent through the use + of a style sheet. + -- + %core; -- Element CLASS, ID and TITLE -- + %i18n; -- Internationalization DIR and LANG -- + CITE %URI; #IMPLIED -- URI for source document or message --> + + + + + + element shall not contain the ,