ofollow" class="ui sha label" href="/tum/network_report_server/commit/30f7226d9aa1b14561d48e5309f57e811e38322f">30f7226d9a first commit 3 yıl önce _createCtor.js 30f7226d9a first commit 3 yıl önce _createCurry.js 30f7226d9a first commit 3 yıl önce _createFind.js 30f7226d9a first commit 3 yıl önce _createFlow.js 30f7226d9a first commit 3 yıl önce _createHybrid.js 30f7226d9a first commit 3 yıl önce _createInverter.js 30f7226d9a first commit 3 yıl önce _createMathOperation.js 30f7226d9a first commit 3 yıl önce _createOver.js 30f7226d9a first commit 3 yıl önce _createPadding.js 30f7226d9a first commit 3 yıl önce _createPartial.js 30f7226d9a first commit 3 yıl önce _createRange.js 30f7226d9a first commit 3 yıl önce _createRecurry.js 30f7226d9a first commit 3 yıl önce _createRelationalOperation.js 30f7226d9a first commit 3 yıl önce _createRound.js 30f7226d9a first commit 3 yıl önce _createSet.js 30f7226d9a first commit 3 yıl önce _createToPairs.js 30f7226d9a first commit 3 yıl önce _createWrap.js 30f7226d9a first commit 3 yıl önce _customDefaultsAssignIn.js 30f7226d9a first commit 3 yıl önce _customDefaultsMerge.js 30f7226d9a first commit 3 yıl önce _customOmitClone.js 30f7226d9a first commit 3 yıl önce _deburrLetter.js 30f7226d9a first commit 3 yıl önce _defineProperty.js 30f7226d9a first commit 3 yıl önce _equalArrays.js 30f7226d9a first commit 3 yıl önce _equalByTag.js 30f7226d9a first commit 3 yıl önce _equalObjects.js 30f7226d9a first commit 3 yıl önce _escapeHtmlChar.js 30f7226d9a first commit 3 yıl önce _escapeStringChar.js 30f7226d9a first commit 3 yıl önce _flatRest.js 30f7226d9a first commit 3 yıl önce _freeGlobal.js 30f7226d9a first commit 3 yıl önce _getAllKeys.js 30f7226d9a first commit 3 yıl önce _getAllKeysIn.js 30f7226d9a first commit 3 yıl önce _getData.js 30f7226d9a first commit 3 yıl önce _getFuncName.js 30f7226d9a first commit 3 yıl önce _getHolder.js 30f7226d9a first commit 3 yıl önce _getMapData.js 30f7226d9a first commit 3 yıl önce _getMatchData.js 30f7226d9a first commit 3 yıl önce _getNative.js 30f7226d9a first commit 3 yıl önce _getPrototype.js 30f7226d9a first commit 3 yıl önce _getRawTag.js 30f7226d9a first commit 3 yıl önce _getSymbols.js 30f7226d9a first commit 3 yıl önce _getSymbolsIn.js 30f7226d9a first commit 3 yıl önce _getTag.js 30f7226d9a first commit 3 yıl önce _getValue.js 30f7226d9a first commit 3 yıl önce _getView.js 30f7226d9a first commit 3 yıl önce _getWrapDetails.js 30f7226d9a first commit 3 yıl önce _hasPath.js 30f7226d9a first commit 3 yıl önce _hasUnicode.js 30f7226d9a first commit 3 yıl önce _hasUnicodeWord.js 30f7226d9a first commit 3 yıl önce _hashClear.js 30f7226d9a first commit 3 yıl önce _hashDelete.js 30f7226d9a first commit 3 yıl önce _hashGet.js 30f7226d9a first commit 3 yıl önce _hashHas.js 30f7226d9a first commit 3 yıl önce _hashSet.js 30f7226d9a first commit 3 yıl önce _initCloneArray.js 30f7226d9a first commit 3 yıl önce _initCloneByTag.js 30f7226d9a first commit 3 yıl önce _initCloneObject.js 30f7226d9a first commit 3 yıl önce _insertWrapDetails.js 30f7226d9a first commit 3 yıl önce _isFlattenable.js 30f7226d9a first commit 3 yıl önce _isIndex.js 30f7226d9a first commit 3 yıl önce _isIterateeCall.js 30f7226d9a first commit 3 yıl önce _isKey.js 30f7226d9a first commit 3 yıl önce _isKeyable.js 30f7226d9a first commit 3 yıl önce _isLaziable.js 30f7226d9a first commit 3 yıl önce _isMaskable.js 30f7226d9a first commit 3 yıl önce _isMasked.js 30f7226d9a first commit 3 yıl önce _isPrototype.js 30f7226d9a first commit 3 yıl önce _isStrictComparable.js 30f7226d9a first commit 3 yıl önce _iteratorToArray.js 30f7226d9a first commit 3 yıl önce _lazyClone.js 30f7226d9a first commit 3 yıl önce _lazyReverse.js 30f7226d9a first commit 3 yıl önce _lazyValue.js 30f7226d9a first commit 3 yıl önce _listCacheClear.js 30f7226d9a first commit 3 yıl önce _listCacheDelete.js 30f7226d9a first commit 3 yıl önce _listCacheGet.js 30f7226d9a first commit 3 yıl önce _listCacheHas.js 30f7226d9a first commit 3 yıl önce _listCacheSet.js 30f7226d9a first commit 3 yıl önce _mapCacheClear.js 30f7226d9a first commit 3 yıl önce _mapCacheDelete.js 30f7226d9a first commit 3 yıl önce _mapCacheGet.js 30f7226d9a first commit 3 yıl önce _mapCacheHas.js 30f7226d9a first commit 3 yıl önce _mapCacheSet.js 30f7226d9a first commit 3 yıl önce _mapToArray.js 30f7226d9a first commit 3 yıl önce _matchesStrictComparable.js 30f7226d9a first commit 3 yıl önce _memoizeCapped.js 30f7226d9a first commit 3 yıl önce _mergeData.js 30f7226d9a first commit 3 yıl önce _metaMap.js 30f7226d9a first commit 3 yıl önce _nativeCreate.js 30f7226d9a first commit 3 yıl önce _nativeKeys.js 30f7226d9a first commit 3 yıl önce _nativeKeysIn.js 30f7226d9a first commit 3 yıl önce _nodeUtil.js 30f7226d9a first commit 3 yıl önce _objectToString.js 30f7226d9a first commit 3 yıl önce _overArg.js 30f7226d9a first commit 3 yıl önce _overRest.js 30f7226d9a first commit 3 yıl önce _parent.js 30f7226d9a first commit 3 yıl önce _reEscape.js 30f7226d9a first commit 3 yıl önce _reEvaluate.js 30f7226d9a first commit 3 yıl önce _reInterpolate.js 30f7226d9a first commit 3 yıl önce _realNames.js 30f7226d9a first commit 3 yıl önce _reorder.js 30f7226d9a first commit 3 yıl önce _replaceHolders.js 30f7226d9a first commit 3 yıl önce _root.js 30f7226d9a first commit 3 yıl önce _safeGet.js 30f7226d9a first commit 3 yıl önce _setCacheAdd.js 30f7226d9a first commit 3 yıl önce _setCacheHas.js 30f7226d9a first commit 3 yıl önce _setData.js 30f7226d9a first commit 3 yıl önce _setToArray.js 30f7226d9a first commit 3 yıl önce _setToPairs.js 30f7226d9a first commit 3 yıl önce _setToString.js 30f7226d9a first commit 3 yıl önce _setWrapToString.js 30f7226d9a first commit 3 yıl önce _shortOut.js 30f7226d9a first commit 3 yıl önce _shuffleSelf.js 30f7226d9a first commit 3 yıl önce _stackClear.js 30f7226d9a first commit 3 yıl önce _stackDelete.js 30f7226d9a first commit 3 yıl önce _stackGet.js 30f7226d9a first commit 3 yıl önce _stackHas.js 30f7226d9a first commit 3 yıl önce _stackSet.js 30f7226d9a first commit 3 yıl önce _strictIndexOf.js 30f7226d9a first commit 3 yıl önce _strictLastIndexOf.js 30f7226d9a first commit 3 yıl önce _stringSize.js 30f7226d9a first commit 3 yıl önce _stringToArray.js 30f7226d9a first commit 3 yıl önce _stringToPath.js 30f7226d9a first commit 3 yıl önce _toKey.js 30f7226d9a first commit 3 yıl önce _toSource.js 30f7226d9a first commit 3 yıl önce _trimmedEndIndex.js 30f7226d9a first commit 3 yıl önce _unescapeHtmlChar.js 30f7226d9a first commit 3 yıl önce _unicodeSize.js 30f7226d9a first commit 3 yıl önce _unicodeToArray.js 30f7226d9a first commit 3 yıl önce _unicodeWords.js 30f7226d9a first commit 3 yıl önce _updateWrapDetails.js 30f7226d9a first commit 3 yıl önce _wrapperClone.js 30f7226d9a first commit 3 yıl önce add.js 30f7226d9a first commit 3 yıl önce after.js 30f7226d9a first commit 3 yıl önce array.js 30f7226d9a first commit 3 yıl önce ary.js 30f7226d9a first commit 3 yıl önce assign.js 30f7226d9a first commit 3 yıl önce assignIn.js 30f7226d9a first commit 3 yıl önce assignInWith.js 30f7226d9a first commit 3 yıl önce assignWith.js 30f7226d9a first commit 3 yıl önce at.js 30f7226d9a first commit 3 yıl önce attempt.js 30f7226d9a first commit 3 yıl önce before.js 30f7226d9a first commit 3 yıl önce bind.js 30f7226d9a first commit 3 yıl önce bindAll.js 30f7226d9a first commit 3 yıl önce bindKey.js 30f7226d9a first commit 3 yıl önce camelCase.js 30f7226d9a first commit 3 yıl önce capitalize.js 30f7226d9a first commit 3 yıl önce castArray.js 30f7226d9a first commit 3 yıl önce ceil.js 30f7226d9a first commit 3 yıl önce chain.js 30f7226d9a first commit 3 yıl önce chunk.js 30f7226d9a first commit 3 yıl önce clamp.js 30f7226d9a first commit 3 yıl önce clone.js 30f7226d9a first commit 3 yıl önce cloneDeep.js 30f7226d9a first commit 3 yıl önce cloneDeepWith.js 30f7226d9a first commit 3 yıl önce cloneWith.js 30f7226d9a first commit 3 yıl önce collection.js 30f7226d9a first commit 3 yıl önce commit.js 30f7226d9a first commit 3 yıl önce compact.js 30f7226d9a first commit 3 yıl önce concat.js 30f7226d9a first commit 3 yıl önce cond.js 30f7226d9a first commit 3 yıl önce conforms.js 30f7226d9a first commit 3 yıl önce conformsTo.js 30f7226d9a first commit 3 yıl önce constant.js 30f7226d9a first commit 3 yıl önce core.js 30f7226d9a first commit 3 yıl önce core.min.js 30f7226d9a first commit 3 yıl önce countBy.js 30f7226d9a first commit 3 yıl önce create.js 30f7226d9a first commit 3 yıl önce curry.js 30f7226d9a first commit 3 yıl önce curryRight.js 30f7226d9a first commit 3 yıl önce date.js 30f7226d9a first commit 3 yıl önce debounce.js 30f7226d9a first commit 3 yıl önce deburr.js 30f7226d9a first commit 3 yıl önce defaultTo.js 30f7226d9a first commit 3 yıl önce defaults.js 30f7226d9a first commit 3 yıl önce defaultsDeep.js 30f7226d9a first commit 3 yıl önce defer.js 30f7226d9a first commit 3 yıl önce delay.js 30f7226d9a first commit 3 yıl önce difference.js 30f7226d9a first commit 3 yıl önce differenceBy.js 30f7226d9a first commit 3 yıl önce differenceWith.js 30f7226d9a first commit 3 yıl önce divide.js 30f7226d9a first commit 3 yıl önce drop.js 30f7226d9a first commit 3 yıl önce dropRight.js 30f7226d9a first commit 3 yıl önce dropRightWhile.js 30f7226d9a first commit 3 yıl önce dropWhile.js 30f7226d9a first commit 3 yıl önce each.js 30f7226d9a first commit 3 yıl önce eachRight.js 30f7226d9a first commit 3 yıl önce endsWith.js 30f7226d9a first commit 3 yıl önce entries.js 30f7226d9a first commit 3 yıl önce entriesIn.js 30f7226d9a first commit 3 yıl önce eq.js 30f7226d9a first commit 3 yıl önce escape.js 30f7226d9a first commit 3 yıl önce escapeRegExp.js 30f7226d9a first commit 3 yıl önce every.js 30f7226d9a first commit 3 yıl önce extend.js 30f7226d9a first commit 3 yıl önce extendWith.js 30f7226d9a first commit 3 yıl önce fill.js 30f7226d9a first commit 3 yıl önce filter.js 30f7226d9a first commit 3 yıl önce find.js 30f7226d9a first commit 3 yıl önce findIndex.js 30f7226d9a first commit 3 yıl önce findKey.js 30f7226d9a first commit 3 yıl önce findLast.js 30f7226d9a first commit 3 yıl önce findLastIndex.js 30f7226d9a first commit 3 yıl önce findLastKey.js 30f7226d9a first commit 3 yıl önce first.js 30f7226d9a first commit 3 yıl önce flake.lock 30f7226d9a first commit 3 yıl önce flake.nix 30f7226d9a first commit 3 yıl önce flatMap.js 30f7226d9a first commit 3 yıl önce flatMapDeep.js 30f7226d9a first commit 3 yıl önce flatMapDepth.js 30f7226d9a first commit 3 yıl önce flatten.js 30f7226d9a first commit 3 yıl önce flattenDeep.js 30f7226d9a first commit 3 yıl önce flattenDepth.js 30f7226d9a first commit 3 yıl önce flip.js 30f7226d9a first commit 3 yıl önce floor.js 30f7226d9a first commit 3 yıl önce flow.js 30f7226d9a first commit 3 yıl önce flowRight.js 30f7226d9a first commit 3 yıl önce forEach.js 30f7226d9a first commit 3 yıl önce forEachRight.js 30f7226d9a first commit 3 yıl önce forIn.js 30f7226d9a first commit 3 yıl önce forInRight.js 30f7226d9a first commit 3 yıl önce forOwn.js 30f7226d9a first commit 3 yıl önce forOwnRight.js 30f7226d9a first commit 3 yıl önce fp.js 30f7226d9a first commit 3 yıl önce fromPairs.js 30f7226d9a first commit 3 yıl önce function.js 30f7226d9a first commit 3 yıl önce functions.js 30f7226d9a first commit 3 yıl önce functionsIn.js 30f7226d9a first commit 3 yıl önce get.js 30f7226d9a first commit 3 yıl önce groupBy.js 30f7226d9a first commit 3 yıl önce gt.js 30f7226d9a first commit 3 yıl önce gte.js 30f7226d9a first commit 3 yıl önce has.js 30f7226d9a first commit 3 yıl önce hasIn.js 30f7226d9a first commit 3 yıl önce head.js 30f7226d9a first commit 3 yıl önce identity.js 30f7226d9a first commit 3 yıl önce inRange.js 30f7226d9a first commit 3 yıl önce includes.js 30f7226d9a first commit 3 yıl önce index.js 30f7226d9a first commit 3 yıl önce indexOf.js 30f7226d9a first commit 3 yıl önce initial.js 30f7226d9a first commit 3 yıl önce intersection.js 30f7226d9a first commit 3 yıl önce intersectionBy.js 30f7226d9a first commit 3 yıl önce intersectionWith.js 30f7226d9a first commit 3 yıl önce invert.js 30f7226d9a first commit 3 yıl önce invertBy.js 30f7226d9a first commit 3 yıl önce invoke.js 30f7226d9a first commit 3 yıl önce invokeMap.js 30f7226d9a first commit 3 yıl önce isArguments.js 30f7226d9a first commit 3 yıl önce isArray.js 30f7226d9a first commit 3 yıl önce isArrayBuffer.js 30f7226d9a first commit 3 yıl önce isArrayLike.js 30f7226d9a first commit 3 yıl önce isArrayLikeObject.js 30f7226d9a first commit 3 yıl önce isBoolean.js 30f7226d9a first commit 3 yıl önce isBuffer.js 30f7226d9a first commit 3 yıl önce isDate.js 30f7226d9a first commit 3 yıl önce isElement.js 30f7226d9a first commit 3 yıl önce isEmpty.js 30f7226d9a first commit 3 yıl önce isEqual.js 30f7226d9a first commit 3 yıl önce isEqualWith.js 30f7226d9a first commit 3 yıl önce isError.js 30f7226d9a first commit 3 yıl önce isFinite.js 30f7226d9a first commit 3 yıl önce isFunction.js 30f7226d9a first commit 3 yıl önce isInteger.js 30f7226d9a first commit 3 yıl önce isLength.js 30f7226d9a first commit 3 yıl önce isMap.js 30f7226d9a first commit 3 yıl önce isMatch.js 30f7226d9a first commit 3 yıl önce isMatchWith.js 30f7226d9a first commit 3 yıl önce isNaN.js 30f7226d9a first commit 3 yıl önce isNative.js 30f7226d9a first commit 3 yıl önce isNil.js 30f7226d9a first commit 3 yıl önce isNull.js 30f7226d9a first commit 3 yıl önce isNumber.js 30f7226d9a first commit 3 yıl önce isObject.js 30f7226d9a first commit 3 yıl önce isObjectLike.js 30f7226d9a first commit 3 yıl önce isPlainObject.js 30f7226d9a first commit 3 yıl önce isRegExp.js 30f7226d9a first commit 3 yıl önce isSafeInteger.js 30f7226d9a first commit 3 yıl önce isSet.js 30f7226d9a first commit 3 yıl önce isString.js 30f7226d9a first commit 3 yıl önce isSymbol.js 30f7226d9a first commit 3 yıl önce isTypedArray.js 30f7226d9a first commit 3 yıl önce isUndefined.js 30f7226d9a first commit 3 yıl önce isWeakMap.js 30f7226d9a first commit 3 yıl önce isWeakSet.js 30f7226d9a first commit 3 yıl önce iteratee.js 30f7226d9a first commit 3 yıl önce join.js 30f7226d9a first commit 3 yıl önce kebabCase.js 30f7226d9a first commit 3 yıl önce keyBy.js 30f7226d9a first commit 3 yıl önce keys.js 30f7226d9a first commit 3 yıl önce keysIn.js 30f7226d9a first commit 3 yıl önce lang.js 30f7226d9a first commit 3 yıl önce last.js 30f7226d9a first commit 3 yıl önce lastIndexOf.js 30f7226d9a first commit 3 yıl önce lodash.js 30f7226d9a first commit 3 yıl önce lodash.min.js 30f7226d9a first commit 3 yıl önce lowerCase.js 30f7226d9a first commit 3 yıl önce lowerFirst.js 30f7226d9a first commit 3 yıl önce lt.js 30f7226d9a first commit 3 yıl önce lte.js 30f7226d9a first commit 3 yıl önce map.js 30f7226d9a first commit 3 yıl önce mapKeys.js 30f7226d9a first commit 3 yıl önce mapValues.js 30f7226d9a first commit 3 yıl önce matches.js 30f7226d9a first commit 3 yıl önce matchesProperty.js 30f7226d9a first commit 3 yıl önce math.js 30f7226d9a first commit 3 yıl önce max.js 30f7226d9a first commit 3 yıl önce maxBy.js 30f7226d9a first commit 3 yıl önce mean.js 30f7226d9a first commit 3 yıl önce meanBy.js 30f7226d9a first commit 3 yıl önce memoize.js 30f7226d9a first commit 3 yıl önce merge.js 30f7226d9a first commit 3 yıl önce mergeWith.js 30f7226d9a first commit 3 yıl önce method.js 30f7226d9a first commit 3 yıl önce methodOf.js 30f7226d9a first commit 3 yıl önce min.js 30f7226d9a first commit 3 yıl önce minBy.js 30f7226d9a first commit 3 yıl önce mixin.js 30f7226d9a first commit 3 yıl önce multiply.js 30f7226d9a first commit 3 yıl önce negate.js 30f7226d9a first commit 3 yıl önce next.js 30f7226d9a first commit 3 yıl önce noop.js 30f7226d9a first commit 3 yıl önce now.js 30f7226d9a first commit 3 yıl önce nth.js 30f7226d9a first commit 3 yıl önce nthArg.js 30f7226d9a first commit 3 yıl önce number.js 30f7226d9a first commit 3 yıl önce object.js 30f7226d9a first commit 3 yıl önce omit.js 30f7226d9a first commit 3 yıl önce omitBy.js 30f7226d9a first commit 3 yıl önce once.js 30f7226d9a first commit 3 yıl önce orderBy.js 30f7226d9a first commit 3 yıl önce over.js 30f7226d9a first commit 3 yıl önce overArgs.js 30f7226d9a first commit 3 yıl önce overEvery.js 30f7226d9a first commit 3 yıl önce overSome.js 30f7226d9a first commit 3 yıl önce package.json 30f7226d9a first commit 3 yıl önce pad.js 30f7226d9a first commit 3 yıl önce padEnd.js 30f7226d9a first commit 3 yıl önce padStart.js 30f7226d9a first commit 3 yıl önce parseInt.js 30f7226d9a first commit 3 yıl önce partial.js 30f7226d9a first commit 3 yıl önce partialRight.js 30f7226d9a first commit 3 yıl önce partition.js 30f7226d9a first commit 3 yıl önce pick.js 30f7226d9a first commit 3 yıl önce pickBy.js 30f7226d9a first commit 3 yıl önce plant.js 30f7226d9a first commit 3 yıl önce property.js 30f7226d9a first commit 3 yıl önce propertyOf.js 30f7226d9a first commit 3 yıl önce pull.js 30f7226d9a first commit 3 yıl önce pullAll.js 30f7226d9a first commit 3 yıl önce pullAllBy.js 30f7226d9a first commit 3 yıl önce pullAllWith.js 30f7226d9a first commit 3 yıl önce pullAt.js 30f7226d9a first commit 3 yıl önce random.js 30f7226d9a first commit 3 yıl önce range.js 30f7226d9a first commit 3 yıl önce rangeRight.js 30f7226d9a first commit 3 yıl önce rearg.js 30f7226d9a first commit 3 yıl önce reduce.js 30f7226d9a first commit 3 yıl önce reduceRight.js 30f7226d9a first commit 3 yıl önce reject.js 30f7226d9a first commit 3 yıl önce release.md 30f7226d9a first commit 3 yıl önce remove.js 30f7226d9a first commit 3 yıl önce repeat.js 30f7226d9a first commit 3 yıl önce replace.js 30f7226d9a first commit 3 yıl önce rest.js 30f7226d9a first commit 3 yıl önce result.js 30f7226d9a first commit 3 yıl önce reverse.js 30f7226d9a first commit 3 yıl önce round.js 30f7226d9a first commit 3 yıl önce sample.js 30f7226d9a first commit 3 yıl önce sampleSize.js 30f7226d9a first commit 3 yıl önce seq.js 30f7226d9a first commit 3 yıl önce set.js 30f7226d9a first commit 3 yıl önce setWith.js 30f7226d9a first commit 3 yıl önce shuffle.js 30f7226d9a first commit 3 yıl önce size.js 30f7226d9a first commit 3 yıl önce slice.js 30f7226d9a first commit 3 yıl önce snakeCase.js 30f7226d9a first commit 3 yıl önce some.js 30f7226d9a first commit 3 yıl önce sortBy.js 30f7226d9a first commit 3 yıl önce sortedIndex.js 30f7226d9a first commit 3 yıl önce sortedIndexBy.js 30f7226d9a first commit 3 yıl önce sortedIndexOf.js 30f7226d9a first commit 3 yıl önce sortedLastIndex.js 30f7226d9a first commit 3 yıl önce sortedLastIndexBy.js 30f7226d9a first commit 3 yıl önce sortedLastIndexOf.js 30f7226d9a first commit 3 yıl önce sortedUniq.js 30f7226d9a first commit 3 yıl önce sortedUniqBy.js 30f7226d9a first commit 3 yıl önce split.js 30f7226d9a first commit 3 yıl önce spread.js 30f7226d9a first commit 3 yıl önce startCase.js 30f7226d9a first commit 3 yıl önce startsWith.js 30f7226d9a first commit 3 yıl önce string.js 30f7226d9a first commit 3 yıl önce stubArray.js 30f7226d9a first commit 3 yıl önce stubFalse.js 30f7226d9a first commit 3 yıl önce stubObject.js 30f7226d9a first commit 3 yıl önce stubString.js 30f7226d9a first commit 3 yıl önce stubTrue.js 30f7226d9a first commit 3 yıl önce subtract.js 30f7226d9a first commit 3 yıl önce sum.js 30f7226d9a first commit 3 yıl önce sumBy.js 30f7226d9a first commit 3 yıl önce tail.js 30f7226d9a first commit 3 yıl önce take.js 30f7226d9a first commit 3 yıl önce takeRight.js 30f7226d9a first commit 3 yıl önce takeRightWhile.js 30f7226d9a first commit 3 yıl önce takeWhile.js 30f7226d9a first commit 3 yıl önce tap.js 30f7226d9a first commit 3 yıl önce template.js 30f7226d9a first commit 3 yıl önce templateSettings.js 30f7226d9a first commit 3 yıl önce throttle.js 30f7226d9a first commit 3 yıl önce thru.js 30f7226d9a first commit 3 yıl önce times.js 30f7226d9a first commit 3 yıl önce toArray.js 30f7226d9a first commit 3 yıl önce toFinite.js 30f7226d9a first commit 3 yıl önce toInteger.js 30f7226d9a first commit 3 yıl önce toIterator.js 30f7226d9a first commit 3 yıl önce toJSON.js 30f7226d9a first commit 3 yıl önce toLength.js 30f7226d9a first commit 3 yıl önce toLower.js 30f7226d9a first commit 3 yıl önce toNumber.js 30f7226d9a first commit 3 yıl önce toPairs.js 30f7226d9a first commit 3 yıl önce toPairsIn.js 30f7226d9a first commit 3 yıl önce toPath.js 30f7226d9a first commit 3 yıl önce toPlainObject.js 30f7226d9a first commit 3 yıl önce toSafeInteger.js 30f7226d9a first commit 3 yıl önce toString.js 30f7226d9a first commit 3 yıl önce toUpper.js 30f7226d9a first commit 3 yıl önce transform.js 30f7226d9a first commit 3 yıl önce trim.js 30f7226d9a first commit 3 yıl önce trimEnd.js 30f7226d9a first commit 3 yıl önce trimStart.js 30f7226d9a first commit 3 yıl önce truncate.js 30f7226d9a first commit 3 yıl önce unary.js 30f7226d9a first commit 3 yıl önce unescape.js 30f7226d9a first commit 3 yıl önce union.js 30f7226d9a first commit 3 yıl önce unionBy.js 30f7226d9a first commit 3 yıl önce unionWith.js 30f7226d9a first commit 3 yıl önce uniq.js 30f7226d9a first commit 3 yıl önce uniqBy.js 30f7226d9a first commit 3 yıl önce uniqWith.js 30f7226d9a first commit 3 yıl önce uniqueId.js 30f7226d9a first commit 3 yıl önce unset.js 30f7226d9a first commit 3 yıl önce unzip.js 30f7226d9a first commit 3 yıl önce unzipWith.js 30f7226d9a first commit 3 yıl önce update.js 30f7226d9a first commit 3 yıl önce updateWith.js 30f7226d9a first commit 3 yıl önce upperCase.js 30f7226d9a first commit 3 yıl önce upperFirst.js 30f7226d9a first commit 3 yıl önce util.js 30f7226d9a first commit 3 yıl önce value.js 30f7226d9a first commit 3 yıl önce valueOf.js 30f7226d9a first commit 3 yıl önce values.js 30f7226d9a first commit 3 yıl önce valuesIn.js 30f7226d9a first commit 3 yıl önce without.js 30f7226d9a first commit 3 yıl önce words.js 30f7226d9a first commit 3 yıl önce wrap.js 30f7226d9a first commit 3 yıl önce wrapperAt.js 30f7226d9a first commit 3 yıl önce wrapperChain.js 30f7226d9a first commit 3 yıl önce wrapperLodash.js 30f7226d9a first commit 3 yıl önce wrapperReverse.js 30f7226d9a first commit 3 yıl önce wrapperValue.js 30f7226d9a first commit 3 yıl önce xor.js 30f7226d9a first commit 3 yıl önce xorBy.js 30f7226d9a first commit 3 yıl önce xorWith.js 30f7226d9a first commit 3 yıl önce zip.js 30f7226d9a first commit 3 yıl önce zipObject.js 30f7226d9a first commit 3 yıl önce zipObjectDeep.js 30f7226d9a first commit 3 yıl önce zipWith.js 30f7226d9a first commit 3 yıl önce

README.md

lodash v4.17.21

The Lodash library exported as Node.js modules.

Installation

Using npm:

$ npm i -g npm
$ npm i --save lodash

In Node.js:

// Load the full build.
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load the FP build for immutable auto-curried iteratee-first data-last methods.
var fp = require('lodash/fp');

// Load method categories.
var array = require('lodash/array');
var object = require('lodash/fp/object');

// Cherry-pick methods for smaller browserify/rollup/webpack bundles.
var at = require('lodash/at');
var curryN = require('lodash/fp/curryN');

See the package source for more details.

Note:
Install n_ for Lodash use in the Node.js < 6 REPL.

Support

Tested in Chrome 74-75, Firefox 66-67, IE 11, Edge 18, Safari 11-12, & Node.js 8-12.
Automated browser & CI test runs are available.

tum/whitesports - Gogs: Simplico Git Service

Nessuna descrizione

subscriptions.php 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896
  1. <?php
  2. /**
  3. * Module Name: Subscriptions
  4. * Module Description: Let visitors subscribe to new posts and comments via email
  5. * Sort Order: 9
  6. * Recommendation Order: 8
  7. * First Introduced: 1.2
  8. * Requires Connection: Yes
  9. * Requires User Connection: Yes
  10. * Auto Activate: No
  11. * Module Tags: Social
  12. * Feature: Engagement
  13. * Additional Search Queries: subscriptions, subscription, email, follow, followers, subscribers, signup
  14. */
  15. use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
  16. add_action( 'jetpack_modules_loaded', 'jetpack_subscriptions_load' );
  17. function jetpack_subscriptions_load() {
  18. Jetpack::enable_module_configurable( __FILE__ );
  19. }
  20. /**
  21. * Cherry picks keys from `$_SERVER` array.
  22. *
  23. * @since 6.0.0
  24. *
  25. * @return array An array of server data.
  26. */
  27. function jetpack_subscriptions_cherry_pick_server_data() {
  28. $data = array();
  29. foreach ( $_SERVER as $key => $value ) {
  30. if ( ! is_string( $value ) || 0 === strpos( $key, 'HTTP_COOKIE' ) ) {
  31. continue;
  32. }
  33. if ( 0 === strpos( $key, 'HTTP_' ) || in_array( $key, array( 'REMOTE_ADDR', 'REQUEST_URI', 'DOCUMENT_URI' ), true ) ) {
  34. $data[ $key ] = $value;
  35. }
  36. }
  37. return $data;
  38. }
  39. class Jetpack_Subscriptions {
  40. public $jetpack = false;
  41. public static $hash;
  42. /**
  43. * Singleton
  44. * @static
  45. */
  46. static function init() {
  47. static $instance = false;
  48. if ( !$instance ) {
  49. $instance = new Jetpack_Subscriptions;
  50. }
  51. return $instance;
  52. }
  53. function __construct() {
  54. $this->jetpack = Jetpack::init();
  55. // Don't use COOKIEHASH as it could be shared across installs && is non-unique in multisite.
  56. // @see: https://twitter.com/nacin/status/378246957451333632
  57. self::$hash = md5( get_option( 'siteurl' ) );
  58. add_filter( 'jetpack_xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
  59. // @todo remove sync from subscriptions and move elsewhere...
  60. // Add Configuration Page
  61. add_action( 'admin_init', array( $this, 'configure' ) );
  62. // Catch subscription widget submits
  63. if ( isset( $_REQUEST['jetpack_subscriptions_widget'] ) )
  64. add_action( 'template_redirect', array( $this, 'widget_submit' ) );
  65. // Set up the comment subscription checkboxes
  66. add_filter( 'comment_form_submit_field', array( $this, 'comment_subscribe_init' ), 10, 2 );
  67. // Catch comment posts and check for subscriptions.
  68. add_action( 'comment_post', array( $this, 'comment_subscribe_submit' ), 50, 2 );
  69. // Adds post meta checkbox in the post submit metabox
  70. add_action( 'post_submitbox_misc_actions', array( $this, 'subscription_post_page_metabox' ) );
  71. add_action( 'transition_post_status', array( $this, 'maybe_send_subscription_email' ), 10, 3 );
  72. add_filter( 'jetpack_published_post_flags', array( $this, 'set_post_flags' ), 10, 2 );
  73. add_filter( 'post_updated_messages', array( $this, 'update_published_message' ), 18, 1 );
  74. // Set "social_notifications_subscribe" option during the first-time activation.
  75. add_action( 'jetpack_activate_module_subscriptions', array( $this, 'set_social_notifications_subscribe' ) );
  76. }
  77. /**
  78. * Jetpack_Subscriptions::xmlrpc_methods()
  79. *
  80. * Register subscriptions methods with the Jetpack XML-RPC server.
  81. * @param array $methods
  82. */
  83. function xmlrpc_methods( $methods ) {
  84. return array_merge(
  85. $methods,
  86. array(
  87. 'jetpack.subscriptions.subscribe' => array( $this, 'subscribe' ),
  88. )
  89. );
  90. }
  91. /*
  92. * Disable Subscribe on Single Post
  93. * Register post meta
  94. */
  95. function subscription_post_page_metabox() {
  96. if (
  97. /**
  98. * Filter whether or not to show the per-post subscription option.
  99. *
  100. * @module subscriptions
  101. *
  102. * @since 3.7.0
  103. *
  104. * @param bool true = show checkbox option on all new posts | false = hide the option.
  105. */
  106. ! apply_filters( 'jetpack_allow_per_post_subscriptions', false ) )
  107. {
  108. return;
  109. }
  110. if ( has_filter( 'jetpack_subscriptions_exclude_these_categories' ) || has_filter( 'jetpack_subscriptions_include_only_these_categories' ) ) {
  111. return;
  112. }
  113. global $post;
  114. $disable_subscribe_value = get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true );
  115. // only show checkbox if post hasn't been published and is a 'post' post type.
  116. if ( get_post_status( $post->ID ) !== 'publish' && get_post_type( $post->ID ) == 'post' ) :
  117. // Nonce it
  118. wp_nonce_field( 'disable_subscribe', 'disable_subscribe_nonce' );
  119. ?>
  120. <div class="misc-pub-section">
  121. <label for="_jetpack_dont_email_post_to_subs"><?php _e( 'Jetpack Subscriptions:', 'jetpack' ); ?></label><br>
  122. <input type="checkbox" name="_jetpack_dont_email_post_to_subs" id="jetpack-per-post-subscribe" value="1" <?php checked( $disable_subscribe_value, 1, true ); ?> />
  123. <?php _e( 'Don&#8217;t send this to subscribers', 'jetpack' ); ?>
  124. </div>
  125. <?php endif;
  126. }
  127. /**
  128. * Checks whether or not the post should be emailed to subscribers
  129. *
  130. * It checks for the following things in order:
  131. * - Usage of filter jetpack_subscriptions_exclude_these_categories
  132. * - Usage of filter jetpack_subscriptions_include_only_these_categories
  133. * - Existence of the per-post checkbox option
  134. *
  135. * Only one of these can be used at any given time.
  136. *
  137. * @param $new_status string - the "new" post status of the transition when saved
  138. * @param $old_status string - the "old" post status of the transition when saved
  139. * @param $post obj - The post object
  140. */
  141. function maybe_send_subscription_email( $new_status, $old_status, $post ) {
  142. if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
  143. return;
  144. }
  145. // Make sure that the checkbox is preseved
  146. if ( ! empty( $_POST['disable_subscribe_nonce'] ) && wp_verify_nonce( $_POST['disable_subscribe_nonce'], 'disable_subscribe' ) ) {
  147. $set_checkbox = isset( $_POST['_jetpack_dont_email_post_to_subs'] ) ? 1 : 0;
  148. update_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', $set_checkbox );
  149. }
  150. }
  151. function update_published_message( $messages ) {
  152. global $post;
  153. if ( ! $this->should_email_post_to_subscribers( $post ) ) {
  154. return $messages;
  155. }
  156. $view_post_link_html = sprintf( ' <a href="%1$s">%2$s</a>',
  157. esc_url( get_permalink( $post ) ),
  158. __( 'View post', 'jetpack' )
  159. );
  160. $messages['post'][6] = sprintf(
  161. /* translators: Message shown after a post is published */
  162. esc_html__( 'Post published and sending emails to subscribers.', 'jetpack' )
  163. ) . $view_post_link_html;
  164. return $messages;
  165. }
  166. public function should_email_post_to_subscribers( $post ) {
  167. $should_email = true;
  168. if ( get_post_meta( $post->ID, '_jetpack_dont_email_post_to_subs', true ) ) {
  169. return false;
  170. }
  171. // Only posts are currently supported
  172. if ( $post->post_type !== 'post' ) {
  173. return false;
  174. }
  175. // Private posts are not sent to subscribers.
  176. if ( 'private' === $post->post_status ) {
  177. return false;
  178. }
  179. /**
  180. * Array of categories that will never trigger subscription emails.
  181. *
  182. * Will not send subscription emails from any post from within these categories.
  183. *
  184. * @module subscriptions
  185. *
  186. * @since 3.7.0
  187. *
  188. * @param array $args Array of category slugs or ID's.
  189. */
  190. $excluded_categories = apply_filters( 'jetpack_subscriptions_exclude_these_categories', array() );
  191. // Never email posts from these categories
  192. if ( ! empty( $excluded_categories ) && in_category( $excluded_categories, $post->ID ) ) {
  193. $should_email = false;
  194. }
  195. /**
  196. * ONLY send subscription emails for these categories
  197. *
  198. * Will ONLY send subscription emails to these categories.
  199. *
  200. * @module subscriptions
  201. *
  202. * @since 3.7.0
  203. *
  204. * @param array $args Array of category slugs or ID's.
  205. */
  206. $only_these_categories = apply_filters( 'jetpack_subscriptions_exclude_all_categories_except', array() );
  207. // Only emails posts from these categories
  208. if ( ! empty( $only_these_categories ) && ! in_category( $only_these_categories, $post->ID ) ) {
  209. $should_email = false;
  210. }
  211. return $should_email;
  212. }
  213. function set_post_flags( $flags, $post ) {
  214. $flags['send_subscription'] = $this->should_email_post_to_subscribers( $post );
  215. return $flags;
  216. }
  217. /**
  218. * Jetpack_Subscriptions::configure()
  219. *
  220. * Jetpack Subscriptions configuration screen.
  221. */
  222. function configure() {
  223. // Create the section
  224. add_settings_section(
  225. 'jetpack_subscriptions',
  226. __( 'Jetpack Subscriptions Settings', 'jetpack' ),
  227. array( $this, 'subscriptions_settings_section' ),
  228. 'discussion'
  229. );
  230. /** Subscribe to Posts ***************************************************/
  231. add_settings_field(
  232. 'jetpack_subscriptions_post_subscribe',
  233. __( 'Follow Blog', 'jetpack' ),
  234. array( $this, 'subscription_post_subscribe_setting' ),
  235. 'discussion',
  236. 'jetpack_subscriptions'
  237. );
  238. register_setting(
  239. 'discussion',
  240. 'stb_enabled'
  241. );
  242. /** Subscribe to Comments ******************************************************/
  243. add_settings_field(
  244. 'jetpack_subscriptions_comment_subscribe',
  245. __( 'Follow Comments', 'jetpack' ),
  246. array( $this, 'subscription_comment_subscribe_setting' ),
  247. 'discussion',
  248. 'jetpack_subscriptions'
  249. );
  250. register_setting(
  251. 'discussion',
  252. 'stc_enabled'
  253. );
  254. /** Email me whenever: Someone follows my blog ***************************************************/
  255. /* @since 8.1 */
  256. add_settings_section(
  257. 'notifications_section',
  258. __( 'Someone follows my blog', 'jetpack' ),
  259. array( $this, 'social_notifications_subscribe_section' ),
  260. 'discussion'
  261. );
  262. add_settings_field(
  263. 'jetpack_subscriptions_social_notifications_subscribe',
  264. __( 'Email me whenever', 'jetpack' ),
  265. array( $this, 'social_notifications_subscribe_field' ),
  266. 'discussion',
  267. 'notifications_section'
  268. );
  269. register_setting(
  270. 'discussion',
  271. 'social_notifications_subscribe',
  272. array( $this, 'social_notifications_subscribe_validate' )
  273. );
  274. /** Subscription Messaging Options ******************************************************/
  275. register_setting(
  276. 'reading',
  277. 'subscription_options',
  278. array( $this, 'validate_settings' )
  279. );
  280. add_settings_section(
  281. 'email_settings',
  282. __( 'Follower Settings', 'jetpack' ),
  283. array( $this, 'reading_section' ),
  284. 'reading'
  285. );
  286. add_settings_field(
  287. 'invitation',
  288. __( 'Blog follow email text', 'jetpack' ),
  289. array( $this, 'setting_invitation' ),
  290. 'reading',
  291. 'email_settings'
  292. );
  293. add_settings_field(
  294. 'comment-follow',
  295. __( 'Comment follow email text', 'jetpack' ),
  296. array( $this, 'setting_comment_follow' ),
  297. 'reading',
  298. 'email_settings'
  299. );
  300. }
  301. /**
  302. * Discussions setting section blurb
  303. *
  304. */
  305. function subscriptions_settings_section() {
  306. ?>
  307. <p id="jetpack-subscriptions-settings"><?php _e( 'Change whether your visitors can subscribe to your posts or comments or both.', 'jetpack' ); ?></p>
  308. <?php
  309. }
  310. /**
  311. * Post Subscriptions Toggle
  312. *
  313. */
  314. function subscription_post_subscribe_setting() {
  315. $stb_enabled = get_option( 'stb_enabled', 1 ); ?>
  316. <p class="description">
  317. <input type="checkbox" name="stb_enabled" id="jetpack-post-subscribe" value="1" <?php checked( $stb_enabled, 1 ); ?> />
  318. <?php _e( "Show a <em>'follow blog'</em> option in the comment form", 'jetpack' ); ?>
  319. </p>
  320. <?php
  321. }
  322. /**
  323. * Comments Subscriptions Toggle
  324. *
  325. */
  326. function subscription_comment_subscribe_setting() {
  327. $stc_enabled = get_option( 'stc_enabled', 1 ); ?>
  328. <p class="description">
  329. <input type="checkbox" name="stc_enabled" id="jetpack-comment-subscribe" value="1" <?php checked( $stc_enabled, 1 ); ?> />
  330. <?php _e( "Show a <em>'follow comments'</em> option in the comment form", 'jetpack' ); ?>
  331. </p>
  332. <?php
  333. }
  334. /**
  335. * Someone follows my blog section
  336. *
  337. * @since 8.1
  338. */
  339. public function social_notifications_subscribe_section() {
  340. // Atypical usage here. We emit jquery to move subscribe notification checkbox to be with the rest of the email notification settings
  341. ?>
  342. <script type="text/javascript">
  343. jQuery( function( $ ) {
  344. var table = $( '#social_notifications_subscribe' ).parents( 'table:first' ),
  345. header = table.prevAll( 'h2:first' ),
  346. newParent = $( '#moderation_notify' ).parent( 'label' ).parent();
  347. if ( ! table.length || ! header.length || ! newParent.length ) {
  348. return;
  349. }
  350. newParent.append( '<br/>' ).append( table.end().parent( 'label' ).siblings().andSelf() );
  351. header.remove();
  352. table.remove();
  353. } );
  354. </script>
  355. <?php
  356. }
  357. /**
  358. * Someone follows my blog Toggle
  359. *
  360. * @since 8.1
  361. */
  362. public function social_notifications_subscribe_field() {
  363. $checked = (int) ( 'on' === get_option( 'social_notifications_subscribe', 'on' ) );
  364. ?>
  365. <label>
  366. <input type="checkbox" name="social_notifications_subscribe" id="social_notifications_subscribe" value="1" <?php checked( $checked ); ?> />
  367. <?php
  368. /* translators: this is a label for a setting that starts with "Email me whenever" */
  369. esc_html_e( 'Someone follows my blog', 'jetpack' );
  370. ?>
  371. </label>
  372. <?php
  373. }
  374. /**
  375. * Validate "Someone follows my blog" option
  376. *
  377. * @since 8.1
  378. *
  379. * @param String $input the input string to be validated.
  380. * @return string on|off
  381. */
  382. public function social_notifications_subscribe_validate( $input ) {
  383. // If it's not set (was unchecked during form submission) or was set to off (during option update), return 'off'.
  384. if ( ! $input || 'off' === $input ) {
  385. return 'off';
  386. }
  387. // Otherwise we return 'on'.
  388. return 'on';
  389. }
  390. function validate_settings( $settings ) {
  391. global $allowedposttags;
  392. $default = $this->get_default_settings();
  393. // Blog Follow
  394. $settings['invitation'] = trim( wp_kses( $settings['invitation'], $allowedposttags ) );
  395. if ( empty( $settings['invitation'] ) )
  396. $settings['invitation'] = $default['invitation'];
  397. // Comments Follow (single post)
  398. $settings['comment_follow'] = trim( wp_kses( $settings['comment_follow'], $allowedposttags ) );
  399. if ( empty( $settings['comment_follow'] ) )
  400. $settings['comment_follow'] = $default['comment_follow'];
  401. return $settings;
  402. }
  403. public function reading_section() {
  404. echo '<p id="follower-settings">';
  405. _e( 'These settings change emails sent from your blog to followers.', 'jetpack' );
  406. echo '</p>';
  407. }
  408. public function setting_invitation() {
  409. $settings = $this->get_settings();
  410. echo '<textarea name="subscription_options[invitation]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['invitation'] ) . '</textarea>';
  411. echo '<p><span class="description">'.__( 'Introduction text sent when someone follows your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ).'</span></p>';
  412. }
  413. public function setting_comment_follow() {
  414. $settings = $this->get_settings();
  415. echo '<textarea name="subscription_options[comment_follow]" class="large-text" cols="50" rows="5">' . esc_textarea( $settings['comment_follow'] ) . '</textarea>';
  416. echo '<p><span class="description">'.__( 'Introduction text sent when someone follows a post on your blog. (Site and confirmation details will be automatically added for you.)', 'jetpack' ).'</span></p>';
  417. }
  418. function get_default_settings() {
  419. return array(
  420. 'invitation' => __( "Howdy.\n\nYou recently followed this blog's posts. This means you will receive each new post by email.\n\nTo activate, click confirm below. If you believe this is an error, ignore this message and we'll never bother you again.", 'jetpack' ),
  421. 'comment_follow' => __( "Howdy.\n\nYou recently followed one of my posts. This means you will receive an email when new comments are posted.\n\nTo activate, click confirm below. If you believe this is an error, ignore this message and we'll never bother you again.", 'jetpack' )
  422. );
  423. }
  424. function get_settings() {
  425. return wp_parse_args( (array) get_option( 'subscription_options', array() ), $this->get_default_settings() );
  426. }
  427. /**
  428. * Jetpack_Subscriptions::subscribe()
  429. *
  430. * Send a synchronous XML-RPC subscribe to blog posts or subscribe to post comments request.
  431. *
  432. * @param string $email
  433. * @param array $post_ids (optional) defaults to 0 for blog posts only: array of post IDs to subscribe to blog's posts
  434. * @param bool $async (optional) Should the subscription be performed asynchronously? Defaults to true.
  435. *
  436. * @return true|WP_Error true on success
  437. * invalid_email : not a valid email address
  438. * invalid_post_id : not a valid post ID
  439. * unknown_post_id : unknown post
  440. * not_subscribed : strange error. Jetpack servers at WordPress.com could subscribe the email.
  441. * disabled : Site owner has disabled subscriptions.
  442. * active : Already subscribed.
  443. * pending : Tried to subscribe before but the confirmation link is never clicked. No confirmation email is sent.
  444. * unknown : strange error. Jetpack servers at WordPress.com returned something malformed.
  445. * unknown_status : strange error. Jetpack servers at WordPress.com returned something I didn't understand.
  446. */
  447. function subscribe( $email, $post_ids = 0, $async = true, $extra_data = array() ) {
  448. if ( !is_email( $email ) ) {
  449. return new WP_Error( 'invalid_email' );
  450. }
  451. if ( !$async ) {
  452. $xml = new Jetpack_IXR_ClientMulticall();
  453. }
  454. foreach ( (array) $post_ids as $post_id ) {
  455. $post_id = (int) $post_id;
  456. if ( $post_id < 0 ) {
  457. return new WP_Error( 'invalid_post_id' );
  458. } else if ( $post_id && !$post = get_post( $post_id ) ) {
  459. return new WP_Error( 'unknown_post_id' );
  460. }
  461. if ( $async ) {
  462. XMLRPC_Async_Call::add_call( 'jetpack.subscribeToSite', 0, $email, $post_id, serialize( $extra_data ) ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
  463. } else {
  464. $xml->addCall( 'jetpack.subscribeToSite', $email, $post_id, serialize( $extra_data ) );
  465. }
  466. }
  467. if ( $async ) {
  468. return;
  469. }
  470. // Call
  471. $xml->query();
  472. if ( $xml->isError() ) {
  473. return $xml->get_jetpack_error();
  474. }
  475. $responses = $xml->getResponse();
  476. $r = array();
  477. foreach ( (array) $responses as $response ) {
  478. if ( isset( $response['faultCode'] ) || isset( $response['faultString'] ) ) {
  479. $r[] = $xml->get_jetpack_error( $response['faultCode'], $response['faultString'] );
  480. continue;
  481. }
  482. if ( !is_array( $response[0] ) || empty( $response[0]['status'] ) ) {
  483. $r[] = new WP_Error( 'unknown' );
  484. continue;
  485. }
  486. switch ( $response[0]['status'] ) {
  487. case 'error':
  488. $r[] = new WP_Error( 'not_subscribed' );
  489. continue 2;
  490. case 'disabled':
  491. $r[] = new WP_Error( 'disabled' );
  492. continue 2;
  493. case 'active':
  494. $r[] = new WP_Error( 'active' );
  495. continue 2;
  496. case 'confirming':
  497. $r[] = true;
  498. continue 2;
  499. case 'pending':
  500. $r[] = new WP_Error( 'pending' );
  501. continue 2;
  502. default:
  503. $r[] = new WP_Error( 'unknown_status', (string) $response[0]['status'] );
  504. continue 2;
  505. }
  506. }
  507. return $r;
  508. }
  509. /**
  510. * Jetpack_Subscriptions::widget_submit()
  511. *
  512. * When a user submits their email via the blog subscription widget, check the details and call the subsribe() method.
  513. */
  514. function widget_submit() {
  515. // Check the nonce.
  516. if ( is_user_logged_in() ) {
  517. check_admin_referer( 'blogsub_subscribe_' . get_current_blog_id() );
  518. }
  519. if ( empty( $_REQUEST['email'] ) || ! is_string( $_REQUEST['email'] ) )
  520. return false;
  521. $redirect_fragment = false;
  522. if ( isset( $_REQUEST['redirect_fragment'] ) ) {
  523. $redirect_fragment = preg_replace( '/[^a-z0-9_-]/i', '', $_REQUEST['redirect_fragment'] );
  524. }
  525. if ( !$redirect_fragment || ! is_string( $redirect_fragment ) ) {
  526. $redirect_fragment = 'subscribe-blog';
  527. }
  528. $subscribe = Jetpack_Subscriptions::subscribe(
  529. $_REQUEST['email'],
  530. 0,
  531. false,
  532. array(
  533. 'source' => 'widget',
  534. 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
  535. 'comment_status' => '',
  536. 'server_data' => jetpack_subscriptions_cherry_pick_server_data(),
  537. )
  538. );
  539. if ( is_wp_error( $subscribe ) ) {
  540. $error = $subscribe->get_error_code();
  541. } else {
  542. $error = false;
  543. foreach ( $subscribe as $response ) {
  544. if ( is_wp_error( $response ) ) {
  545. $error = $response->get_error_code();
  546. break;
  547. }
  548. }
  549. }
  550. switch ( $error ) {
  551. case false:
  552. $result = 'success';
  553. break;
  554. case 'invalid_email':
  555. $result = $error;
  556. break;
  557. case 'blocked_email':
  558. $result = 'opted_out';
  559. break;
  560. case 'active':
  561. $result = 'already';
  562. break;
  563. case 'flooded_email':
  564. $result = 'many_pending_subs';
  565. break;
  566. case 'pending':
  567. $result = 'pending';
  568. break;
  569. default:
  570. $result = 'error';
  571. break;
  572. }
  573. $redirect = add_query_arg( 'subscribe', $result );
  574. /**
  575. * Fires on each subscription form submission.
  576. *
  577. * @module subscriptions
  578. *
  579. * @since 3.7.0
  580. *
  581. * @param string $result Result of form submission: success, invalid_email, already, error.
  582. */
  583. do_action( 'jetpack_subscriptions_form_submission', $result );
  584. wp_safe_redirect( "$redirect#$redirect_fragment" );
  585. exit;
  586. }
  587. /**
  588. * Jetpack_Subscriptions::comment_subscribe_init()
  589. *
  590. * Set up and add the comment subscription checkbox to the comment form.
  591. *
  592. * @param string $submit_button HTML markup for the submit field.
  593. * @param array $args Arguments passed to `comment_form()`.
  594. */
  595. function comment_subscribe_init( $submit_button, $args ) {
  596. global $post;
  597. $comments_checked = '';
  598. $blog_checked = '';
  599. // Check for a comment / blog submission and set a cookie to retain the setting and check the boxes.
  600. if ( isset( $_COOKIE[ 'jetpack_comments_subscribe_' . self::$hash . '_' . $post->ID ] ) ) {
  601. $comments_checked = ' checked="checked"';
  602. }
  603. if ( isset( $_COOKIE[ 'jetpack_blog_subscribe_' . self::$hash ] ) ) {
  604. $blog_checked = ' checked="checked"';
  605. }
  606. // Some themes call this function, don't show the checkbox again
  607. remove_action( 'comment_form', 'subscription_comment_form' );
  608. // Check if Mark Jaquith's Subscribe to Comments plugin is active - if so, suppress Jetpack checkbox
  609. $str = '';
  610. if ( FALSE === has_filter( 'comment_form', 'show_subscription_checkbox' ) && 1 == get_option( 'stc_enabled', 1 ) && empty( $post->post_password ) && 'post' == get_post_type() ) {
  611. // Subscribe to comments checkbox
  612. $str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_comments" id="subscribe_comments" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $comments_checked . ' /> ';
  613. $comment_sub_text = __( 'Notify me of follow-up comments by email.', 'jetpack' );
  614. $str .= '<label class="subscribe-label" id="subscribe-label" for="subscribe_comments">' . esc_html(
  615. /**
  616. * Filter the Subscribe to comments text appearing below the comment form.
  617. *
  618. * @module subscriptions
  619. *
  620. * @since 3.4.0
  621. *
  622. * @param string $comment_sub_text Subscribe to comments text.
  623. */
  624. apply_filters( 'jetpack_subscribe_comment_label', $comment_sub_text )
  625. ) . '</label>';
  626. $str .= '</p>';
  627. }
  628. if ( 1 == get_option( 'stb_enabled', 1 ) ) {
  629. // Subscribe to blog checkbox
  630. $str .= '<p class="comment-subscription-form"><input type="checkbox" name="subscribe_blog" id="subscribe_blog" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;"' . $blog_checked . ' /> ';
  631. $blog_sub_text = __( 'Notify me of new posts by email.', 'jetpack' );
  632. $str .= '<label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">' . esc_html(
  633. /**
  634. * Filter the Subscribe to blog text appearing below the comment form.
  635. *
  636. * @module subscriptions
  637. *
  638. * @since 3.4.0
  639. *
  640. * @param string $comment_sub_text Subscribe to blog text.
  641. */
  642. apply_filters( 'jetpack_subscribe_blog_label', $blog_sub_text )
  643. ) . '</label>';
  644. $str .= '</p>';
  645. }
  646. /**
  647. * Filter the output of the subscription options appearing below the comment form.
  648. *
  649. * @module subscriptions
  650. *
  651. * @since 1.2.0
  652. *
  653. * @param string $str Comment Subscription form HTML output.
  654. */
  655. $str = apply_filters( 'jetpack_comment_subscription_form', $str );
  656. return $str . $submit_button;
  657. }
  658. /**
  659. * Jetpack_Subscriptions::comment_subscribe_init()
  660. *
  661. * When a user checks the comment subscribe box and submits a comment, subscribe them to the comment thread.
  662. */
  663. function comment_subscribe_submit( $comment_id, $approved ) {
  664. if ( 'spam' === $approved ) {
  665. return;
  666. }
  667. $comment = get_comment( $comment_id );
  668. // Set cookies for this post/comment
  669. $this->set_cookies( isset( $_REQUEST['subscribe_comments'] ), $comment->comment_post_ID, isset( $_REQUEST['subscribe_blog'] ) );
  670. if ( !isset( $_REQUEST['subscribe_comments'] ) && !isset( $_REQUEST['subscribe_blog'] ) )
  671. return;
  672. $post_ids = array();
  673. if ( isset( $_REQUEST['subscribe_comments'] ) )
  674. $post_ids[] = $comment->comment_post_ID;
  675. if ( isset( $_REQUEST['subscribe_blog'] ) )
  676. $post_ids[] = 0;
  677. $result = Jetpack_Subscriptions::subscribe(
  678. $comment->comment_author_email,
  679. $post_ids,
  680. true,
  681. array(
  682. 'source' => 'comment-form',
  683. 'widget-in-use' => is_active_widget( false, false, 'blog_subscription', true ) ? 'yes' : 'no',
  684. 'comment_status' => $approved,
  685. 'server_data' => jetpack_subscriptions_cherry_pick_server_data(),
  686. )
  687. );
  688. /**
  689. * Fires on each comment subscription form submission.
  690. *
  691. * @module subscriptions
  692. *
  693. * @since 5.5.0
  694. *
  695. * @param NULL|WP_Error $result Result of form submission: NULL on success, WP_Error otherwise.
  696. * @param array $post_ids An array of post IDs that the user subscribed to, 0 means blog subscription.
  697. */
  698. do_action( 'jetpack_subscriptions_comment_form_submission', $result, $post_ids );
  699. }
  700. /**
  701. * Jetpack_Subscriptions::set_cookies()
  702. *
  703. * Set a cookie to save state on the comment and post subscription checkboxes.
  704. *
  705. * @param bool $subscribe_to_post Whether the user chose to subscribe to subsequent comments on this post.
  706. * @param int $post_id If $subscribe_to_post is true, the post ID they've subscribed to.
  707. * @param bool $subscribe_to_blog Whether the user chose to subscribe to all new posts on the blog.
  708. */
  709. function set_cookies( $subscribe_to_post = false, $post_id = null, $subscribe_to_blog = false ) {
  710. $post_id = (int) $post_id;
  711. /** This filter is already documented in core/wp-includes/comment-functions.php */
  712. $cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
  713. /**
  714. * Filter the Jetpack Comment cookie path.
  715. *
  716. * @module subscriptions
  717. *
  718. * @since 2.5.0
  719. *
  720. * @param string COOKIEPATH Cookie path.
  721. */
  722. $cookie_path = apply_filters( 'jetpack_comment_cookie_path', COOKIEPATH );
  723. /**
  724. * Filter the Jetpack Comment cookie domain.
  725. *
  726. * @module subscriptions
  727. *
  728. * @since 2.5.0
  729. *
  730. * @param string COOKIE_DOMAIN Cookie domain.
  731. */
  732. $cookie_domain = apply_filters( 'jetpack_comment_cookie_domain', COOKIE_DOMAIN );
  733. if ( $subscribe_to_post && $post_id >= 0 ) {
  734. setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
  735. } else {
  736. setcookie( 'jetpack_comments_subscribe_' . self::$hash . '_' . $post_id, '', time() - 3600, $cookie_path, $cookie_domain );
  737. }
  738. if ( $subscribe_to_blog ) {
  739. setcookie( 'jetpack_blog_subscribe_' . self::$hash, 1, time() + $cookie_lifetime, $cookie_path, $cookie_domain );
  740. } else {
  741. setcookie( 'jetpack_blog_subscribe_' . self::$hash, '', time() - 3600, $cookie_path, $cookie_domain );
  742. }
  743. }
  744. /**
  745. * Set the social_notifications_subscribe option to `off` when the Subscriptions module is activated in the first time.
  746. *
  747. * @since 8.1
  748. *
  749. * @return null
  750. */
  751. function set_social_notifications_subscribe() {
  752. if ( false === get_option( 'social_notifications_subscribe' ) ) {
  753. add_option( 'social_notifications_subscribe', 'off' );
  754. }
  755. }
  756. }
  757. Jetpack_Subscriptions::init();
  758. include dirname( __FILE__ ) . '/subscriptions/views.php';